结构型设计模式:装饰器模式

简介: 结构型设计模式:装饰器模式


设计模式分类

设计模式可以分为三种类型:创建型设计模式、结构型设计模式和行为型设计模式。

创建型设计模式:这些模式涉及到对象的创建机制,包括简单工厂模式、工厂方法模式、抽象工厂模式、单例模式、建造者模式和原型模式。

结构型设计模式:这些模式涉及到类和对象的组合,包括适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式和代理模式。

行为型设计模式:这些模式涉及到对象之间的通信和交互,包括责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式模板方法模式和访问者模式。

本文是对结构型设计模式中的装饰器、组合设计模式的一个总结。每个设计模式的定义都比较晦涩,可以直接看代码理解。

设计模式的设计原则

依赖倒置:高层模块不应该依赖低层模块,两者都应该依赖抽象; 抽象不应该依赖具体实现,具体实现应该依赖于抽象; (记住依赖抽象就好了)。

开放封闭:一个类应该对扩展(组合和继承)开放,对修改关闭;

面向接口:不将变量类型声明为某个特定的具体类,而是声明为某个接口;

客户程序无需获知对象的具体类型,只需要知道对象所具有的接口;

减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案;(记住只暴露接口,只调用接口)。

封装变化点:将稳定点和变化点分离,扩展修改变化点;让稳定点和变化点的实现层次分离;

单一职责:一个类应该仅有一个引起它变化的原因; (就是变化点不要太多)。

里氏替换:子类型必须能够替换掉它的父类型;主要出现在子类覆盖父类实现,原来使用父类型的程序可能出现错误;覆盖了父类方法却没有实现父类方法的职责;( 就是子类可以覆盖父类的方法,但是得保证父类必要的功能)。

接口隔离:不应该强迫客户依赖于它们不用的方法;

一般用于处理一个类拥有比较多的接口,而这些接口涉及到很多职责;

客户端不应该依赖它不需要的接口。

一个类对另一个类的依赖应该建立在最小的接口上。

组合优于继承:继承耦合度高,组合耦合度低;

装饰器模式

动态的给对象添加一些额外的责任,就增加功能来说,装饰比生成子类更为灵活。

用一个菜品计算成本(包括食物和各种调料)的例子说明这个设计模式:

在餐馆需要给食物计算成本,比如面条和加的各种调料:

#include <iostream>
#include <string>
using namespace std;
// 食品类
class Food {
protected:
  string des;
  double price;
public:
  virtual double cost() = 0;
  string getDes() {
    return des;
  }
  void setDes(string des) {
    this->des = des;
  }
  double getPrice() {
    return price;
  }
  void setPrice(double price) {
    this->price = price;
  }
};
// 面条类
class Noodles : public Food {
public:
  double cost() override {
    return getPrice();
  }
};
// 中式面条类
class ChineseNoodles : public Noodles {
public:
  ChineseNoodles() {
    setDes("中式面条");
    setPrice(25.00);
  }
};
// 装饰器类
class Decorator : public Food {
protected:
  Food* desFood;
public:
  Decorator(Food* desFood) {
    this->desFood = desFood;
  }
  double cost() override {
    cout << desFood->getDes() << "价格:" << desFood->getPrice() << "  配料如下:"
      << getDes() << "  价格:" << getPrice() << "  总价" << (getPrice() + desFood->cost()) << endl;
    return getPrice() + desFood->cost();
  }
};
// 孜然类
class Cumin : public Decorator {
public:
  Cumin(Food* desFood) : Decorator(desFood) {
    setDes("孜然");
    setPrice(2.00);
  }
};
// 胡椒类
class Peper : public Decorator {
public:
  Peper(Food* desFood) : Decorator(desFood) {
    setDes("胡椒");
    setPrice(3.00);
  }
};
int main() {
  // 先定义一个被装饰者,返回对象要为最顶层的对象,这样被装饰者才能接受
  Food* noodles = new ChineseNoodles();
  // 定义一个装饰者对象
  Food* cumin = new Cumin(noodles);
  // 输出为:中式面条价格:25配料如下:孜然价格:2总价27
  cout << "-----------面条+孜然------------------------" << endl;
  cumin->cost();
  cout << "-----------面条+胡椒------------------------" << endl;
  Food* peper = new Peper(noodles);
  peper->cost();
  cout << "-----------面条+胡椒+孜然------------------------" << endl;
  peper = new Peper(cumin);
  cout << "面条+胡椒+孜然价格:" <<peper->cost();
  delete cumin;
  delete noodles;
  delete peper;
  return 0;
}

“面条+胡椒+孜然”的例子日志打印比较乱,是由于装饰器类cost打印有嵌套,所以日志打印比较乱。

结构:

  • 被装饰者抽象接口(Food):提供基础功能方法,和装饰方法接口。
  • 具体的被装饰者(Noodles):继承抽象类,实现方法接口。
  • 装饰者公共类(Decorator):实现统一的装饰方法。
  • 具体的修饰者类:定制化装饰者属性。

使用场景:在软件开发过程中,有时想用一些现存的组件(已经定义好的对象)。这些组件可能只是完成一些核心功能。但在不改变其架构的情况下,可以动态地扩展其功能。所以这些都可以采用装饰模式来实现。

特点:

装饰者设计模式是通过组合+继承的形式实现的。

装饰类和被装饰类可以独立发展,不会相互耦合。

装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。


继承和组合的区别:

继承是is A;

组合是has A;

目录
相关文章
|
4月前
|
设计模式 存储 缓存
聊聊Java设计模式-装饰器模式
装饰器模式允许向一个现有的对象添加新的功能,同时不改变其结果。比如Java 中的IO框架中,`FileInputStream`(处理文件)、`ByteArrayInputStream`(处理字节数组)、`BufferedInputStream`(带缓存的处理类)等就是对`InputStream`进行的功能扩展,这就是装饰器模式的典型应用。
27 1
聊聊Java设计模式-装饰器模式
|
4月前
|
设计模式 Java
常用设计模式(工厂方法,抽象工厂,责任链,装饰器模式)
有关设计模式的其他常用模式请参考 单例模式的实现 常见的设计模式(模板与方法,观察者模式,策略模式)
40 2
|
4月前
|
设计模式
设计模式之装饰器模式
设计模式之装饰器模式
|
4月前
|
设计模式
设计模式-装饰器模式
设计模式-装饰器模式
|
19天前
|
设计模式 Go 网络安全
[设计模式 Go实现] 结构型~代理模式
[设计模式 Go实现] 结构型~代理模式
|
19天前
|
设计模式 Go
[设计模式 Go实现] 结构型~装饰模式
[设计模式 Go实现] 结构型~装饰模式
|
19天前
|
设计模式 Go
[设计模式 Go实现] 结构型~适配器模式
[设计模式 Go实现] 结构型~适配器模式
|
2月前
|
设计模式 Java
设计模式之装饰器模式
设计模式之装饰器模式
|
2月前
|
设计模式
装饰器模式--设计模式
装饰器模式--设计模式
18 0
|
4月前
|
设计模式 Java uml
设计模式-装饰器模式
设计模式-装饰器模式
23 0