Подтвердить что ты не робот

Образец декоратора против наследования с примерами

Я экспериментировал с шаблоном декоратора, чтобы расширить функциональность кода, который вы не хотите касаться, например, и я вижу, как его реализовать, но теперь я не уверен, почему вы не просто наследуете исходный класс и расширяете таким образом.

Я прочитал, что шаблон декоратора позволяет добавлять функциональные возможности во время выполнения, тогда как наследование означает его там во время компиляции.

Я не понимаю этого.

Может кто-нибудь объяснить это, привести примеры и объяснить, когда лучше использовать декоратор против наследования.

Спасибо

4b9b3361

Ответ 1

Предположим, вы создали класс View, который отображает ваши элементы определенным образом. Теперь вы решили, что хотите, чтобы версия была прокручиваемой, поэтому вы создаете ScrollableView, который наследует View. Позже вы решите, что хотите иметь версию с рамкой, поэтому теперь вам нужно создать BorderedView и BorderdScrollableView.

Если, с другой стороны, вы можете сделать декоратор для каждого добавленного стиля. У вас были бы следующие классы:

  • Вид
  • ScrollableDecorator
  • BorderedDecorator

Если вы хотите создать окно с ограниченным прокруткой:

new BorderedDecorator(new ScrollableDecorator(new View())).

Таким образом, вы можете настроить любую комбинацию этого только с тремя классами. И вы можете добавлять или удалять их во время выполнения (предположим, вы нажмете кнопку с надписью "добавить границу", теперь вы оберните свое представление с помощью BorderDecorator... в то время как наследование наследования вам нужно реализовать этот класс представления, если вы еще этого не сделали, или вы необходимо создать новый экземпляр представления и скопировать все соответствующие данные из первого представления во второе представление, которое не так просто сделать, как просто добавить или удалить обертки).

Ответ 2

Представьте себе игру, такую ​​как Civilization, где каждый квадрат на карте может иметь множество ресурсов, связанных с ней (например, различные руды, дерево или масло и т.д.).

Если вы использовали прямое наследование, вам нужно создать класс для каждого типа квадрата. Было бы неудобно иметь

public class OilSquare {}
public class OilAndGoldSquare {}
public class GoldAndSilverSquare {}
// etc.

Шаблон Decorator позволяет смешивать и сопоставлять, не создавая жесткую иерархию. Итак, вместо этого вы должны:

public class Square {}
public class GoldDec {}
public class SilverDec {}
public class OilDec {}

// ...

var crazyMix = new GoldDec(new SilverDec(new OilDec(new Square())));

Другими словами, Decorators позволяют создавать поведение конвейера, причем каждый шаг в конвейере может быть заменен другим шагом.

Ответ 3

Как уже было сказано, декораторы хороши для добавления "вариантов" к вещам... Преимущества заключаются в том, что вы можете цеплять методы и т.д. через декораторов.

Представьте себе, что я покупаю автомобиль с вариантами кожаного интерьера, металлической краски и удивительного спойлера...

Существует 8 различных комбинаций из трех вариантов, но с декораторами вам нужны только три дополнительных класса.

Интересная вещь - это то, как работает узор декоратора. В качестве краткого примера:

public class MetallicPaint : Car
{
    private Car car;
    public MetallicPaint(Car wrappedCar)
    {
        car = wrappedCar;
    }

    public decimal Cost()
    {
        return car.Cost() + 500;
    }

    public string Description()
    {
        return car.Description() + ", Metallic Paint";
    }
    public string Speed()
    {
        return car.Speed();
    }
    [... {pass through other methods and properties to the car object}]
}

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

Конечно, если бы у вас было несколько таких декораторов, каждый из которых был встроен в каждую машину, они, в свою очередь, добавили бы свою стоимость, свою часть описания и, возможно, спойлер изменил бы скорость, тогда как другие не...

По сути, это позволяет вам модифицировать объект гораздо более модульным и менее фундаментальным способом, чем наследование. Декораторы всегда должны использоваться так, как если бы они были базовым объектом (в данном случае Car), поэтому они никогда не должны выставлять какие-либо новые методы или свойства, просто слегка изменяя эффект существующих.

Ответ 4

Рисунок декоратора лучше, чем наследование, если у вас есть много функций, которые нужно добавить, и вам также необходимо иметь комбинацию этих функций. Предположим, что ваш базовый класс - A, и вы хотите расширить (украсить) этот базовый класс с помощью функций f1, f2, f3, f4 и некоторой их комбинации (f1, f2) и (f1, f3) и..; поэтому вам потребуется создать в вашей иерархии 4!= 4 * 3 * 2 * 1 = 24 класса (по 4 для каждой функции, а остальные для их комбинации). Хотя, используя декоративный узор, вам нужно будет создать только 4 класса!


для @Seyed Morteza Mousavi в журнале @Razvi: Вы правы, мы можем добавить два свойства Scrollable и Bordered to View, а затем проверить, установлено ли свойство true, чтобы выполнить желаемое поведение. Но для этого требуется, чтобы мы уже знали о количестве требуемой функции (что не относится к шаблону декоратора). в противном случае с каждой новой функцией (скажем, f1), которую мы хотим добавить в наш класс, нам нужно изменить наш основной класс или наследовать основной класс (вы бы сказали) и добавить свойство. При последнем подходе вам потребуется изменить часть кода, который обрабатывает комбинацию функций (это не хорошо, поскольку оно не подчиняется эмпирическому правилу "свободной связи!" )

надеюсь, что это поможет.