装饰者模式 Decorator Pattern

来源:互联网 发布:Ftp端口开放设置 编辑:程序博客网 时间:2024/05/27 09:46

装饰者模式 : 添加新的功能

The Decorator Pattern is another way of wrapping classes(另一个包裹类的方法). The decorator pattern provides a way of attaching additional responsibilities to an object dynamically(把额外的职能动态附加到一个对象上). Decorators give a flexible way extending functionality without subclassing(不通过继承就可扩展功能). Decorators create a chain of objects starting with the decorator objects(从装饰对象开始创建一个对象链).

所有咖啡源自一个类—- 饮料类(不同种类咖啡有不同的价格)
这里写图片描述
但是当我们需要一份摩卡深焙咖啡 : 深焙咖啡(DarkRoast) 加点 摩卡(Mocha) 需要多少钱(cost)? 再加点奶泡(whip)呢?
尝试一:根据不同的调料收取费用:
这里写图片描述
尝试二:利用实例变量&继承:
父类:
这里写图片描述
子类:
这里写图片描述
哪些需求或因素改变时,会影响这个的设计?
1). 调料价格;2). 新的调料出现;3). 合成新的饮料;4). 双倍摩卡.

类设计原则: 类应该对扩展,对修改关闭。
在不修改现有代码的,搭配新的行为。可以使得设计弹性的应对改变,可以接受新的功能应对改变的需求。
观察者模式,可以通过加入新的观察者,来扩展主题(Subject).
有什么模式既允许扩展,又禁止修改? —- 装饰者模式。

摩卡深焙咖啡 :拿一个 深焙咖啡对象,用摩卡装饰,用奶泡装饰,调用cost()方法并依赖委托(delegate)将调料的价钱加上去。
这里写图片描述
这里写图片描述
1). 装饰者和被装饰对象具有相同的超类型;
2). 被装饰者可以被一个或者多个装饰者包装;
3). 装饰者和被装饰者具有相同的超类型,就导致了装饰过的对象可以替代原始对象(这有点类似输出运算符重载,ostream & operator<<(ostream & out, const List & list),假设有个列表类List。out输出流被插入了新的东西,是不是有点像装饰?);
4). 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的;
5). 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
这里写图片描述
这里写图片描述

要想让装饰者取代 被装饰者,装饰者需要和被装饰者(亦即被包装的组件)有相同的“接口”
将装饰者与组件组合时,就是在加入新的行为。所得到的新行为,并不是继承自超类,而是由组合对象得来的。继承Beverage抽象类,是为了有正确的类型,而不是继承它的行为。行为来自装饰者和基础组件,或与其他装饰者之间的组合关系。
因为使用对象组合,可以把所有饮料和调料更有弹性地加以混和与匹配,非常方便。

#include < iostream >using namespace std;// 饮料class Beverage{private:    string description;public:     Beverage()    {        description = "Unknown Beverage";     }    virtual string getDescription()    {        return description;    }    virtual void setDescription(string str)    {        description = str;    }    virtual float cost() { return 0.0f;  };};// 饮料主体class DarkRoast : public Beverage{public:    DarkRoast()    {        setDescription("DarkRoast Beverage");    }    float coat()    {        return 1.99f;    }};// 添加调料(装饰者),如加糖,加奶,加摩卡。所以需要一个装饰类// 为了与饮料兼容,装饰类Decorator也是继承自饮料Beverageclass Decorator : public Beverage{public:    virtual string getDescription() = 0;};// Mochaclass Mocha : public Decorator{    // 如何记录 被装饰者 ?private:    Beverage *beverage;public:    Mocha( Beverage *beverage )    {        this->beverage = beverage;    }    string getDescription()    {        return "Mocha, " +  beverage->getDescription();    }    float cost()    {        return beverage->cost() + .99f;    }};// whipclass Whip : public Decorator{private:    Beverage * beverage;public:    Whip(Beverage *beverage){        this->beverage = beverage;    }    string getDescription()    {        return "Whip, " + beverage->getDescription();    }    float cost()    {        return beverage->cost() + 0.88f;    }};int main(){    Beverage * beverage = new Beverage();    cout << beverage->getDescription().c_str() << "  ,  " << beverage->cost() << endl ;    Beverage * myBeverage = new Whip(new Mocha(new DarkRoast()));/*    Beverage *myBeverage = new DarkRoast();    myBeverage = new Mocha(myBeverage);    myBeverage = new Mocha(myBeverage);    myBeverage = new Whip(myBeverage);*/    cout << myBeverage->getDescription().c_str() << "  ,  " << myBeverage->cost() << endl;    return 0;}

为打印的销售票据添加 表头、页脚 信息。

这里写图片描述

右侧的SalesTicket类。

如果编写的程序只提供一家公司使用,在SalesTicket类中添加对表头和页脚的控制最简单。或者说表头和页脚不变,都是固定内容,该方案行之有效。

但是呢,要是公司不一样呢?也就是说,针对不同的公司,打印不同的表头和页脚。 —-》 是不是又参杂着点策略模式的味道?;分别为不同的公司打印不同表头,分别为不同的公司打印不同的页脚。

但是,万一要添加多个表头,有怎么办?表头的顺序发生改变有怎么办?

⇒ ⇒ Decorator Pattern ⇒⇒ 你的表头你做主(顺序随你定,个数随你挑):
这里写图片描述

/* ==================================================================* 【装饰者模式 Decorator Pattern】 * 作者:朱勇 时间:2016年4月15日 14:46:03* 文件名:源1.cpp* 版本:V1.0.1 * =================================================================== */ #include <iostream>using namespace std;class SalesOrder{public:    virtual void printTicket(){};};// 用来打印发票实体部分(可能是在发票中间,这个是主要内容)class SalesTicket : public SalesOrder{public:    void printTicket()    {        cout << "Ticket Main Content...." << endl;    }};class TicketDecorator : public SalesOrder{public:    virtual void  printTicket(){}};class Header001 : public TicketDecorator{    // 保存被装饰者    SalesOrder * salesOrder;    void printHeader()    {        cout << "Head 001 " << endl;    }public:    Header001(SalesOrder * salesOrder)    {        this->salesOrder = salesOrder;    }    void printTicket()    {        printHeader();        salesOrder->printTicket();    }};class Header002 : public TicketDecorator{    // 保存被装饰者    SalesOrder * salesOrder;    void printHeader()    {        cout << "Head 002 " << endl;    }public:    Header002(SalesOrder * salesOrder)    {        this->salesOrder = salesOrder;    }    void printTicket()    {        printHeader();        salesOrder->printTicket();    }};class Footer001 : public TicketDecorator{    // 保存被装饰者    SalesOrder * salesOrder;    void printFooter()    {        cout << "Footer 001 " << endl;    }public:    Footer001(SalesOrder * salesOrder)    {        this->salesOrder = salesOrder;    }    void printTicket()    {        salesOrder->printTicket();        printFooter();    }};class Footer002 : public TicketDecorator{    // 保存被装饰者    SalesOrder * salesOrder;    void printFooter()    {        cout << "Footer 002 " << endl;    }public:    Footer002(SalesOrder * salesOrder)    {        this->salesOrder = salesOrder;    }    void printTicket()    {        salesOrder->printTicket();        printFooter();    }};int main(){    SalesOrder * salesOrder = new SalesOrder();    /*SalesOrder * a = new SalesTicket();    SalesOrder * b = new Header001(a);    SalesOrder * mySalesOrder = new Footer001(b);*/    SalesOrder * mySalesOrder = new Footer001(new Header001(new SalesTicket()));    mySalesOrder->printTicket();    return 0;}

输出:

Head 001Ticket Main Content....Footer 001

装饰者模式 是 以需要的正确顺序将所需功能串联起来。

维基百科

In object-oriented programming, the decorator pattern (also known as Wrapper, an alternative naming shared with the Adapter pattern) is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering(坚守) to the Single Responsibility Principle (单一职责原则), as it allows functionality to be divided between classes with unique areas of concern.

允许新的功能被添加到一个单独的对象中去,而不影响从相同类继承的另一个类对象的行为。 符合单一职责原则,允许父类按照功能性的被分割成不同的子类。
如:父类SalesOrder专注打印,打印被分割成打印主体和打印装饰体,装饰体被分割成打印表头和打印页脚。 其实这就是单一职责原则。

单一职责原则

单一职责原则(SRP:Single responsibility principle)又称单一功能原则,面向对象五个基本原则(SOLID)之一。它规定一个类应该只有一个发生变化的原因。该原则由罗伯特·C·马丁(Robert C. Martin)于《敏捷软件开发:原则、模式和实践》一书中给出的。马丁表示此原则是基于汤姆·狄马克(Tom DeMarco)和Meilir Page-Jones的著作中的内聚性原则发展出的。 所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。[bing]

To extend the functionality of the graphical window for example by adding a frame to the window, would require extending the window class to create a FramedWindow class. To create a framed window it is necessary to create an object of the FramedWindow class. However it would be impossible to start with a plain window and to extend its functionality at runtime to become a framed window. —-Decorator Pattern
给窗口添加一个scrollBar。
这里写图片描述
Java源码

0 0