part 1 “单一职责”模式

  在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任。

  典型模式

  Decorator
  Bridge

part 2.1 Decorator 装饰模式

  动机(Motivation)

  #在某些情况下我们可能会“过度地使用继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。

  #如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响将为最低?

  模式定义

  动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承)更为灵活(消除重复代码 & 减少子类个数)。——《设计模式》GoF

  代码实现 1 from 课程

  抽象的主体,Stream类代码如下:

class Stream{
public:
virtual char Read(int number)=;
virtual void Seek(int position)=;
virtual void Write(char data)=; virtual ~Stream(){}
};

  Stream抽象基类的具体实现类之一 : FileStream类,代码如下:

class FileStream: public Stream{
public:
virtual char Read(int number){
//读文件流
}
virtual void Seek(int position){
//定位文件流
}
virtual void Write(char data){
//写文件流
}
};

  Stream抽象基类的具体实现之二 : NetworkStream类,代码如下:

class NetworkStream :public Stream{
public:
virtual char Read(int number){
//读网络流
}
virtual void Seek(int position){
//定位网络流
}
virtual void Write(char data){
//写网络流
}
};

  Stream抽象基类的具体实现之三 : MemoryStream类,代码如下:

class MemoryStream :public Stream{
public:
virtual char Read(int number){
//读内存流
}
virtual void Seek(int position){
//定位内存流
}
virtual void Write(char data){
//写内存流
}
};

  DecoraterStream类:维持一个指向Stream的指针,并定义一个与Stream接口一致的接口。代码如下:

DecoratorStream: public Stream{
protected:
Stream* stream;//... DecoratorStream(Stream * stm):stream(stm){ } };

  具体职责之一,加密功能的实现,CryptoStream类代码如下:

class CryptoStream: public DecoratorStream {
public:
CryptoStream(Stream* stm):DecoratorStream(stm){ } virtual char Read(int number){
//额外的加密操作...
stream->Read(number);//读文件流
} virtual void Seek(int position){
//额外的加密操作...
stream::Seek(position);//定位文件流
//额外的加密操作...
} virtual void Write(byte data){
//额外的加密操作...
stream::Write(data);//写文件流
//额外的加密操作...
}
};

  具体职责之二,缓冲功能的实现,BufferedStream类代码如下:

class BufferedStream : public DecoratorStream{

    Stream* stream;//...

public:
BufferedStream(Stream* stm):DecoratorStream(stm){ }
//...
};

  客户端调用代码如下:

void Process(){

    //运行时装配
FileStream* s1=new FileStream(); CryptoStream* s2=new CryptoStream(s1);
BufferedStream* s3=new BufferedStream(s1);
BufferedStream* s4=new BufferedStream(s2); }

  UML结构

  要点总结

  #通过采用组合而非继承的手法, Decorator模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。

  #Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。

  #Decorator模式的目的并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。

  #如果类 A 继承类 B,同时类 A 又组合类 B,则类 A 有99%的可能是 Decorator 设计模式。

part 2.2 Bridge 桥模式

  动机(Motivation)

  #由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个纬度的变化。
  #如何应对这种“多维度的变化”?如何利用面向对象技术来使得类型可以轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度?

  模式定义

  将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。——《设计模式》GoF

  代码实现一 from 课程

  上层抽象类 Messager 类,负责系统的抽象,代码如下:

class Messager{
protected:
MessagerImp* messagerImp;//...
public:
virtual void Login(string username, string password)=;
virtual void SendMessage(string message)=;
virtual void SendPicture(Image image)=; virtual ~Messager(){}
};

  MessagerImp类:与 Messager 同层、负责实现部分。代码如下:

class MessagerImp{
public:
virtual void PlaySound()=;
virtual void DrawShape()=;
virtual void WriteText()=;
virtual void Connect()=; virtual MessagerImp(){}
};

  PCMessagerImp 类和 MobileMessagerImp 类继承于MessagerImp类,负责系统的功能实现部分。代码如下:

class PCMessagerImp : public MessagerImp{
public: virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
}; class MobileMessagerImp : public MessagerImp{
public: virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};

  MessagerLite 类和 MessagerPerfect 类负责系统的业务抽象,代码如下:

class MessagerLite :public Messager {
public:
virtual void Login(string username, string password){ messagerImp->Connect();
//........
} virtual void SendMessage(string message){ messagerImp->WriteText();
//........
} virtual void SendPicture(Image image){ messagerImp->DrawShape();
//........
}
}; class MessagerPerfect :public Messager {
public:
virtual void Login(string username, string password){ messagerImp->PlaySound();
//********
messagerImp->Connect();
//........
} virtual void SendMessage(string message){ messagerImp->PlaySound();
//********
messagerImp->WriteText();
//........
} virtual void SendPicture(Image image){ messagerImp->PlaySound();
//********
messagerImp->DrawShape();
//........
}
};

  用户实现代码如下:

void Process(){
//运行时装配
MessagerImp* mImp=new PCMessagerImp();
Messager *m =new Messager(mImp);
} 

  UML(一)

  代码实现二 from 《大话设计模式》

#include <iostream>

using namespace std;

struct Software {
virtual void run () = ;
}; struct Contact : public Software{
virtual void run () { cout << "通讯录" << endl; }
}; struct Game : public Software {
virtual void run () { cout << "游戏" << endl; }
}; struct Brand {
virtual void run () { _software->run(); }
void setFunction(Software *software){ this->_software = software; }
Software* _software;
}; struct IPhone : public Brand{
virtual void run () override {
cout << "IPhone ";
_software->run();
}
}; struct Mi : public Brand {
//不实现run(),沿用父类虚函数。
}; int main() { Mi *phone1 = new Mi();
IPhone *phone2 = new IPhone(); phone1->setFunction(new Contact());
phone2->setFunction(new Game()); phone1->run();
phone2->run(); return ;
}

  UML(二)

  要点总结

  #Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自纬度的变化,即“子类化”它们。
  #Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。
  #Bridge模式的应用一般在“两个非常强的变化维度”,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。

  #继承转组合:一个伟大的手段。

  #部分 override 纯虚函数的类,依旧是抽象类(C++语法是这样规定的)。

C++设计模式 之 “单一职责”模式:Decorator、Bridge的更多相关文章

  1. 23种设计模式 - 单一职责(Decorator - Bridge)

    其他设计模式 23种设计模式(C++) 每一种都有对应理解的相关代码示例 → Git原码 ⌨ 单一职责 在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀, ...

  2. 设计模式---单一职责模式之装饰模式(Decorator)

    前提:"单一职责"模式 在软件组件的设计中,如果责任划分的不清晰,使用继承,得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任 典型模式(表现 ...

  3. 学习记录:《C++设计模式——李建忠主讲》4.“单一职责”模式

    单一职责模式:在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任. 典型模式:装饰模式(Decorator).桥 ...

  4. JAVA设计模式之单一职责原则

    概念: 就一个类而言应该只有一个因其他变化的原因. 流程: 问题由来:设类或接口类C负责两个不同不同的职责:职责T1,职责T2.当由于职责T1需求改变进而需要修改类C时,可能导致职责T2收到不可预知的 ...

  5. 北风设计模式课程---单一职责原则(Single Responsibility Principle)

    北风设计模式课程---单一职责原则(Single Responsibility Principle) 一.总结 一句话总结: 一个类应该有且只有一个变化的原因:单一职责原则(SRP:Single Re ...

  6. 设计模式---单一职责模式之桥模式(Bridge)

    一:概念 Bridge模式又叫做桥接模式,其实基于类的最小设计原则,通过使用封装,聚合以及继承等行为来让不同的类承担不同的责任他的主要特点是吧抽象与行为实现分离开来,从而可以保持各部分的独立性以及一对 ...

  7. 设计模式学习之桥接模式(Bridge,结构型模式)(15)

    参考地址:http://terrylee.cnblogs.com/archive/2006/02/24/336652.html 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化, ...

  8. 23种设计模式之装饰器模式(Decorator Pattern)

    装饰器模式(Decorator Pattern) 允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包 ...

  9. python 设计模式之装饰器模式 Decorator Pattern

    #写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...

随机推荐

  1. java 中静态变量(类变量)与实例变量 静态方法与实例方法

    静态变量: 在类内部中,方法的外部声明的对象而且加上static; 实例变量: 在类内部中,声明不需要加static; 比如: public class Demo{ int i1=0; static ...

  2. Sublime2或3配置R、Scala、Python交互式环境

    1.Sublime3的下载地址:http://www.sublimetext.com/3 2.刚刚安装的软件是没有PackageControl的,需要在新安装使用 (1)   以前没有安装过Packa ...

  3. 基于Solr和Zookeeper的分布式搜索方案的配置

    1.1 什么是SolrCloud SolrCloud(solr 云)是Solr提供的分布式搜索方案,当你需要大规模,容错,分布式索引和检索能力时使用 SolrCloud.当一个系统的索引数据量少的时候 ...

  4. HDU 2087 - 剪花布条 - [KMP算法]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 Time Limit: 1000/1000 MS (Java/Others) Memory Li ...

  5. 数据恢复:如何恢复Linux中意外删除的Oracle和MySQL数据库

    今天有客户的数据库意外被删除了整个目录中的数据文件,操作系统级别的删除,然而幸运的是这个数据库没有崩溃,仍然处于 open 状态的时候,客户就发现了问题,求助到我们,最终完整地恢复了所有数据文件. 在 ...

  6. Java-idea-eclipse-快捷键【mac,win】

    Mac键盘符号和修饰键说明 ⌘ Command ⇧ Shift ⌥ Option ⌃ Control ↩︎ Return/Enter ⌫ Delete ⌦ 向前删除键(Fn+Delete) ↑ 上箭头 ...

  7. PAT 1021 Deepest Root[并查集、dfs][难]

    1021 Deepest Root (25)(25 分) A graph which is connected and acyclic can be considered a tree. The he ...

  8. soapUI-DataGen

    1.1.1  DataGen 1.1.1.1 概述 – DataGen DataGen TestStep可用于生成要用作TestCases中的输入的数据,例如数字或日期序列,随机选择等.生成的数据可作 ...

  9. jquery 实现iframe 自适应高度

    转自: http://www.cnblogs.com/luluping/archive/2009/04/17/1437843.html 超级简单的方法,也不用写什么判断浏览器高度.宽度啥的.下面的两种 ...

  10. php发送 与接收流文件

    PHP 发送与接收流文件 sendStreamFile.php 把文件以流的形式发送 receiveStreamFile.php 接收流文件并保存到本地 sendStreamFile.php < ...