Альтернатива наследованию. C#

Замена наследованию

В этой статье я расскажу об альтернативе наследованию, а точнее, частичной альтернативе! Всё обсуждение будет вестись в контексте языка программирования C#. Читали предыдущую статью? В ней я касался темы применения наследования для повторного использования уже реализованной функциональности… И тогда я сказал, что применение наследования только для этой цели — не лучший вариант, и обещал рассказать как получить результат без использования наследования. Вот и настало время обсудить эту тему!

Давайте рассмотрим такой пример: у нас есть класс, который предназначен для отправки данных по сети (пусть называется он «Sender»). И нас всё уставало до определенного момента, но потом мы решили, что данные перед отправкой в сеть нужно сжимать, например… Что мы можем сделать? Мы можем написать класс-наследник, базовым для которого будет уже используемый нами класс «Sender». И в классе-наследнике, реализовать дополнительную функциональность (собственно сжатие данных). На практике, это могло бы выглядеть примерно так:

//Класс, отправляющий данные 
class Sender
{
    public void Send(byte[] aData)
    { 
        //Отправка данных
    }

    //Поля класса, для хранения настроек и прочего
}

//Класс, отправляющий данные, сжимая их перед отправкой
class SenderM : Sender
{
    //Модифицированный метод отправки (предварительно сжимающий данные)
    public void SendM(byte[] aData)
    {
        //Сжимаем данные aData

        //Отправляем данные (вызывая метод базового класса)
        base.Send(aData);
    }

    //Какие-то поля класса
}

Обратите внимание, на то, как мы вызвали метод базового класса «Send», в классе наследнике! Для этого, мы использовали ключевое слово base, тем самым, явно указав, что мы хотим вызвать метод базового класса.

Как видно из примера, мы для повторного использования функциональности, применили механизм наследования. И всё бы ничего, но что мы получили в итоге? Задачу мы как-бы решили, но получили следующие побочные эффекты: установили определенные отношения между классами «Sender» и «SenderM» (который нам не были нужны по условию задачи и которые мы даже не сможем полноценно использовать), да еще и заняли единственное вакантное место базового класса.

В C#, у класса, может быть только один родительский класс (но несколько интерфейсов)! И подбирать родителя нужно с умом…

А теперь, я покажу, как можно решить туже задачу (по сути, повторно использовать уже имеющуюся функциональность) без использования наследования… А использовать мы будем так называемую композицию. В двух словах, основной принцип композиции, заключается в том, что объект одного класса содержит в себе (как поле) объект другого класса. Т.е. есть объемлющий объект (например, автомобиль), и содержимый в нем (например, двигатель) объект.

Обратите внимание, композиция подразумевает, что при уничтожении объемлющего объекта, уничтожается и содержимый в нем объект. Это отличает композицию от агрегирования (в случае агрегирования, при уничтожении объемлющего объекта, содержимый объект может существовать дальше).

На практике, решение всё той же задачи (повторного использования кода) с помощью применения композиции может выглядеть примерно так:

//Класс, отправляющий данные 
class Sender
{
    public void Send(byte[] aData)
    { 
        //Отправка данных
    }

    //Поля класса, для хранения настроек и прочего
}

//Класс, отправляющий данные, сжимая их перед отправкой
class SenderM
{
    //Модифицированный метод отправки (предварительно сжимающий данные)
    public void SendM(byte[] aData)
    {
        //Сжимаем данные aData

        //Отправляем данные (вызывая метод содержимого объекта)
        sender.Send(aData);
    }

    //Объект класса Sender
    private Sender sender = new Sender();
 
    //Какие-то другие поля класса...
}

Как видно из примера, кодировать пришлось не на много больше! А результат получен тот-же, только без упомянутых выше побочных эффектов! Но если честно, я не хочу никого агитировать и предлагать отказаться от наследования, нет, это совсем не так. Наследование — это мощный механизм, и он может принести очень много пользы! Я всего лишь, хотел показать, что иметь возможность — не значит, пользоваться её всегда и везде. И применение наследования только для повторного использования некой функциональности — не лучший вариант (хотя и допустимый).

 

 

 

Добавить комментарий