Design Pattern-Introduction to Decorator Pattern

Problem to be solved

Consider a coffee shop charging problem: how to realize flexible coffee price calculation. The coffee shop mainly sells coffee, but later in order to meet the different tastes of different customers, pure coffee was too monotonous, so I considered adding different combinations. After matching with different ingredients, another drink would be formed. In this way, the variety is rich. But then the question also came, how to calculate new and accurate prices for different new varieties. Two options:

第一种: You can use the inheritance method to use pure coffee as the base class. Then, if you need any variety, you can generate a subclass, which can be used as a variety to rewrite the price calculation method, and you can add other functions to this variety. But: a big problem with inheritance is that the realization of such a scheme requires that you first know what varieties are available before deriving various sub-categories. However, if you want to remove some of the existing varieties in the future Or add some content, or even delete this variety directly, it will be very troublesome to always modify the corresponding category, and there is a disadvantage: a lot of seeds will be produced, if there are many varieties, and the difference between each variety is small When it is time, it will be very troublesome to separate them as a class.

第二种: It is to adopt the theme decorator pattern of this article we are going to talk about today . Let’s compare an example in life: a paper photo. If we want to keep this photo longer, we can first plasticize this photo; after plastic packaging, if we think it’s not enough, we may give this photo again. Install a photo frame; if you don’t think you can protect the photo by adding a photo frame, add a glass cover. In this example, we can understand that the photo itself is the object to be decorated, and plastic, photo frame, and glass cover are all used as decorators. Decorators on each layer will not modify the innermost object being decorated. Here we can regard the specific coffee drink as the decorator, and the food or drink to be added as the decorator. Each coffee drink can be decorated by different decorators.

The above problem of calculating prices for different coffee drinks is based on the concept of programming, which is how to transparently add functions to an object and realize the dynamic combination of functions. This is the function of the decorator mode .

Mode definition

The decorator mode can dynamically add functions to an object, and add functions to an object transparently from the outside.透明地给一个对象增加功能,就是说要给一个对象增加功能,但是不能让这个对象知道,也就是不能去修改这个对象

Each decorated person can be decorated by multiple decorators. For example: black coffee (decorated person) can be decorated by milk (decorator), fruit (decorator), and there is no restriction on the order of different decorators.

Implementation

The decorator needs to inherit the same class or implement the same interface as the decorated object (it is said to comply with the same protocol in iOS), and then, in the implementation of the specific decorator, transfer the decorated object [this requires decorator Subject holds a decorated object]

Below is the implemented UML diagram and the call hierarchy diagram between different classes.

  • CoffeeComponent: Coffee base class (also can be interface/protocol)
  • BlackCoffee: The specific coffee is the object to be decorated.
  • CondimentDecorator: The base class of the ingredients (the base class of the decorator), and it needs to be inherited from the base class of the decorate, and it also needs CoffeeComponentto hold a CoffeeComponenttype of attribute.
  • MilkDecorator: Milk decorator, specific decorator object.

As can be seen from the above hierarchical diagram, multi-layer decorators are wrapped layer by layer outside the decorated object, and the invocation of function methods is also a layer-by-layer recursive call to the decorated object. It can be seen from the figure that when the black coffee is decorated with milk, the milk decorator becomes the new decorator, and can be decorated by other decorators in the future, and there is no order requirement among decorators. The sequence can be done according to your own wishes.

//********************************咖啡组件(基类)*********************
@interface CoffeeComponent : NSObject
- (double)getPrice;
@end

@implementation CoffeeComponent//抽象组件,可以写默认实现的方法,也可以用协议实现
- (double)getPrice
{
    return 0.f;
}
@end

//********************************黑咖啡(具体咖啡类)*********************
@interface BlackCoffee : CoffeeComponent//继承于抽象组件的具体组件
- (double)getPrice;
@end

@implementation BlackCoffee
- (double)getPrice
{
    return 5;
}
@end

//********************************装饰者基类*********************
@interface CondimentDecorator : CoffeeComponent//继承于组件的装饰者抽象类
- (instancetype)initWithComponent:(CoffeeComponent *)component;
@property (nonatomic,strong)CoffeeComponent *component;
@end

@implementation CondimentDecorator
- (instancetype)initWithComponent:(CoffeeComponent *)component
{
    if (self = [super init]) {
        _component = component;
    }
    return self;
}
@end
//********************************牛奶装饰者(具体装饰者)*********************
@interface MilkDecorator : CondimentDecorator//继承于抽象佐料装饰者的具体装饰者
@end

@implementation MilkDecorator
- (double)getPrice
{
    NSLog(@"牛奶加了2元");
    return 2 + [self.component getPrice];
}
@end
//在此省略其它装饰者的代码,与牛奶装饰者的代码一样。代码可以查看demo。
//=========================外部调用=====================
    //纯咖啡
    BlackCoffee *blackCoffee = [[BlackCoffee alloc]init];
    //加奶
    MilkDecorator *milkDecorator = [[MilkDecorator alloc]initWithComponent:blackCoffee];
    //加豆浆
    SoyDecorator *soyDecorator = [[SoyDecorator alloc]initWithComponent:milkDecorator];
    //加水果
    FruitDecorator *fruitDecorator = [[FruitDecorator alloc]initWithComponent:soyDecorator];
    NSLog(@"一共多少钱%f",[fruitDecorator getPrice]);

to sum up

  • The decorator pattern is more flexible than inheritance: inheritance is static, and the inherited subclasses have the same functions as the base class, but the decorator pattern can separate functions into different decorators and dynamically choose what functions you want.
  • The essence of decorator mode is dynamic combination : the combination of decorators dynamically can add functions to the decorated objects transparently.
  • The decorator mode can not only add functions, but also fully realize the access of new functions and control functions. It can be controlled when the function of the decorated object is called in the decorator.
  • Disadvantages of the decorator pattern : fine-grained objects will be produced. If a series of complex functions want to subdivide different functions into different decorators, many fine-grained objects will be produced.

Guess you like

Origin blog.csdn.net/doubututou/article/details/109209934