设计原则
1、开闭原则:
描述:对修改关闭,对拓展开启。
作用:
- 软件测试的时候,只对拓展的代码进行检测即可
- 提高代码的可复用性。代码的粒度越小,可复用的可能性就越大。
- 提高软件的可维护性
2、里氏替换原则:
描述:子类可以拓展父类的功能,但不能改变父类的功能,子类可以能够替换父类,继承表达类型抽象。
作用:
- 实现开闭原则的重要方式之一
- 克服了继承中,重写父类的功能造成可复用性变差
- 类的拓展不会给系统带来影响,降低代码出错的可能性
3、单一职责原则:
描述:一个类应仅有一个引起它变化的原因。类的变化方向隐含类的职责。
作用:
- 降低类的复杂度
- 提高代码的复用性
- 提高可维护性
4、依赖倒置原则:
描述:高层模块(稳定)不依赖于底层模块(变化),两者都依赖于抽象(稳定)。抽象(稳定)不依赖于细节(变化),实现细节应依赖于抽象(稳定)。就是程序要依赖于抽象的接口,不应该依赖于具体实现。
作用:
- 降低类间的耦合性
- 提高代码的可读性和可维护性
5、接口隔离原则:
描述:不应该强迫客户程序使用它们不用的方法。接口应该小而完备。
作用:
- 提高系统的内聚性,减少代码的耦合
- 减少项目工程中的代码冗余
- 将庞大的接口分解成多个粒度小的接口,提高系统的灵活性和可维护性
6、迪米特原则:
描述:最小知识原则(Least Knowledge Principle)。如果两个软件实体不发生直接的数据通信的话,不应该使用直接的调用,而是通过第三方转发其调用(增加中间层)。
作用:
- 降低类的耦合,提高类的独立性
- 提高代码的可复用性和拓展性
7、合成复用原则:
描述:优先使用对象组合,而不是类的继承。(类的继承称为“白箱复用”,对象组合称为“黑箱复用”)。
作用:
- 类的继承一定程度上破环了封装性(耦合度高),使用对象组合,可以降低耦合
设计模式
构建型
一、单例模式(singleton)
- 描述:一个类只有一个实例,并提供一个全局访问点。
- 优点:由于单例模式只允许生成一个对象,因此共享该对象可以减少内存,提高运行速度。
- 缺点: 不够灵活。
- 应用场景:1、在类需要被频繁的创建,并且会被频繁的销毁的时候。比如线程池,网络连接池。2、当类需要被共享的场合。3、某类只需要生成一个实例的时候,比如x班班长,x厂厂花等。
-实现方式:
应提供一个公有的静态函数,一个私有的静态成员变量,一个私有的构造函数。
class singleton
{
public:
static singleton* getInstance();
singleton(const singleton&) = delete;//do not duplicate the singleton class
singleton& operator=(const singleton&) = delete;
private:
singleton() = default;
static singleton* singletonPtr;
};
singleton* singleton::singletonPtr = nullptr;
singleton* singleton::getInstance()
{
if(singletonPtr == nullptr)
{
singletonPtr = new singleton();
}
return singletonPtr;
}
二、工厂模式
工厂方法(factory method)
- 描述:定义一个用于创建对象的接口,让子类决定实例化哪一个类,达到一个类的延迟实例化。(实现方式:虚函数)
- 优点:1、可以隔离对象的使用者和具体类型的耦合关系(面对一个经常变化的具体类型,紧耦合关系会削弱软件的鲁棒性)。2、通过面向对象的方式,将实例化对象的的工作延迟到子类,实现了一个拓展(而非更改)的策略。
- 缺点: 每增加一个产品,都需要增加一个具体的产品对象类和具体工厂类,增加了系统的复杂度。
- 应用场景:1、在软件编程中,经常需要面临实例化不同对象的工作,在需求不同的时候,需要实例化的对象的具体类型也不同。在这种情景下,绕开了传统的“new”的创建方式,提供了一种”封装机制“来避免客户程序与”具体对象创建工作“这种紧密耦合的关系。
-实现方式:
class baseProduct
{
public:
virtual baseProduct* getProduct();
};
class A_product : public baseProduct
{
//create the A product
};
class B_product : public baseProduct
{
//create the B product
};
class A_productFactory : public A_product
{
public:
virtual baseProduct* getProduct()
{
return new A_product();
}
};
class B_productFactory : public B_product
{
public:
virtual baseProduct* getProduct()
{
return new B_product();
}
};
抽象工厂(abstract factory)
- 描述:提供一个接口来创建一系列的“相互依赖或者相关的对象”,而无需指定它们具体的类。
- 优点:1、提供一种封装机制来避免客户端和“多系列具体对象创建工作”的紧耦合。2、可以在类的内部产品中对相关联的产品进行统一管理,而不必引入多个新的类来进行管理。
- 缺点: 难以应对"新对象"的需求变动。当增加一个新的产品时,需要对所有的工厂类进行修改。
- 应用场景:当需要创建一系列相互依赖或者相关的对象的时候,使用抽象工厂。
-实现方式:
class A_abstractProduct
{
public:
virtual ~A_abstractProduct()=default;
virtual void doSomething()=0;
};
class B_abstractProduct
{
public:
virtual ~B_abstractProduct()=default;
virtual void doSomething()=0;
};
class abstractFactory
{
public:
virtual ~abstractFactory()=default;
virtual A_abstractProduct* returnProductA()=0;
virtual B_abstractProduct* returnProductB()=0;
};
class A1_concreteProduct : public A_abstractProduct
{
public:
virtual ~A1_concreteProduct()=default;
virtual void doSomething()
{
//work for product A1
}
};
class B1_concreteProduct : public B_abstractProduct
{
public:
virtual ~B1_concreteProduct()=default;
virtual void doSomething()
{
//work for product B1
}
};
class A2_concreteProduct : public A_abstractProduct
{
public:
virtual ~A2_concreteProduct()=default;
virtual void doSomething()
{
//work for product A2
}
};
class B2_concreteProduct : public B_abstractProduct
{
public:
virtual ~B2_concreteProduct()=default;
virtual void doSomething()
{
//work for product B2
}
};
class concreteFactory1 : public abstractFactory
{
public:
virtual ~concreteFactory1()=default;
virtual A_abstractProduct* returnProductA()
{
return new A1_concreteProduct();
}
virtual B_abstractProduct* returnProductB()
{
return new B1_concreteProduct();
}
};
class concreteFactory2 : public abstractFactory
{
public:
virtual ~concreteFactory2()=default;
virtual A_abstractProduct* returnProductA()
{
return new A2_concreteProduct();
}
virtual B_abstractProduct* returnProductB()
{
return new B2_concreteProduct();
}
};
int main(void)
{
//the usage of abstract factory
abstractFactory *productFactory = new concreteFactory1();
A_abstractProduct *productA = productFactory->returnProductA();
}
三、建造者(builder)
- 描述:将一个复杂的对象分解成多个相对简单的部分,然后按照不同的需求分别创建它们,最后构建成一个复杂的对象。建造者注重于对象的组装过程,工厂模式注重对象的组件的创建过程。
- 优点:提供一种“封装机制”来隔离出“复杂对象的各个部分”,从而保持了“稳定构造算法”不随着需求的改变而改变。
- 缺点:难以应对“分步骤构建算法”的需求变动。如果对象的内部变化复杂,该模式会产生很多的建造者类。
- 应用场景:1、用来分步骤地来创建对象。当创建的对象较为复杂,并且由多个部件构成,部件内部的需求变化多,但是构建的顺序是稳定的。各个部件相对独立。
- 实现方式:
class building
{
};
class builder
{
public:
virtual ~builder()=default;
virtual void A_componentPart()=0;
virtual void B_componentPart()=0;
virtual void C_componentPart()=0;
virtual building* getResult()=0;
};
class gradenBuilder : public builder
{
public:
virtual ~gradenBuilder()=default;
virtual void A_componentPart()
{
//do something for finalBuilding part A
}
virtual void B_componentPart()
{
//do something for finalBuilding part B
}
virtual void C_componentPart()
{
//do something for finalBuilding part C
}
virtual building* getResult()
{
return finalBuilding;
}
private:
building* finalBuilding;
};
class buildDirect
{
virtual ~buildDirect()=default;
void givenBuildingPlan(builder* buildingPlan)
{
this->buildingPlan = buildingPlan;
}
building* construct()
{
buildingPlan->A_componentPart();
buildingPlan->B_componentPart();
buildingPlan->C_componentPart();
return buildingPlan->getResult();
}
builder *buildingPlan;
};
int main()
{
//************************the usage of abstract factory************************************************
gradenBuilder *gradenBuilderPlan = new gradenBuilder();
buildDirect *gradenDirector = new buildDirect();
gradenDirector->givenBuildingPlan(gradenBuilderPlan);
building *graden = gradenDirector->construct();
}
四、原型(protoltype)
- 描述:使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
- 优点:可以灵活地动态创建“拥有某些稳定接口”的新对象,这些对象不同实例之间可能只需要一些小改动。同时代价仅仅是注册一个新类的对象原型,然后使用clone即可。
- 缺点:1、单纯地使用系统默认的复制函数只会进行浅拷贝,如果是深拷贝需要另外实现一个复制构造函数。
- 应用场景:在系统中存在大量相同的或相似的对象创建的时候,如果使用传统的构造函数来创建对象,会比较消耗计算资源。使用原型模式可以避免这种缺点。
- 实现方式:
class constractProtoltype
{
public:
virtual ~constractProtoltype();
virtual constractProtoltype* clone() = 0;
};
class concreteProtoltype : public constractProtoltype
{
public:
virtual ~concreteProtoltype()=default;
virtual concreteProtoltype* clone()
{
return new concreteProtoltype(*this); //this is different from factory method
}
};
结构型
五、代理(proxy)
- 描述:为某对象提供一种代理来控制该对象的访问,
- 优点:1、在客户端程序和目标对象间提供了中介来保护目标对象的作用。2、将客户端程序与目标对象分离,降低了系统的耦合度。
- 缺点:1、增加了中间层,导致了处理速度下降。2、增加了系统的复杂度。
- 应用场景:1、当直接访问对象会给使用者或者系统结构带来很多麻烦(比如访问对象的开销很大,查看远程图片或者视频等,或者某些操作需要安全控制,或者需要进程外的访问等)。
- 实现方式:
class abstractSubject
{
public:
virtual ~abstractSubject()=default;
virtual void process(void *argv)=0;
};
class concreteSubject : public abstractSubject
{
public:
virtual ~concreteSubject()=default;
virtual void process(void *argv)
{
//bussiness for concreteSubject
}
};
class subjectProxy
{
public:
virtual ~subjectProxy()=default;
virtual void proxyInterface(void *argv)
{
if(realSubject == nullptr)
{
realSubject = new concreteSubject();
}
realSubject->process(argv);
}
private:
abstractSubject *realSubject;
};
六、适配器(adapter)
- 描述:将一个类的接口的转换成客户程序希望的另一个接口。使得原本由于接口不兼容而不能一起工作的类可以一起工作
- 优点:1、客户端程序可以通过适配器透明地调用目标接口。2、复用了现存的类。3、将目标类和适配者类解耦,解决了目标类和适配器类接口不一致的问题。
- 缺点:适配器类的实现过程比较复杂。
- 应用场景:在开发过程中,遇到某些组件已经存在现有的组件库中,但是与系统的规范不符合,同时重新开发该组件的成本又很高,这种情况下应当使用适配器模式。
- 实现方式:
class existedComponent
{
public:
virtual ~existedComponent()=default;
virtual void existedProcess()
{
//bussiness about existed component
}
};
class adapterInterface
{
public:
adapterInterface(existedComponent *adapteeComponent):adapteeComponent(adapteeComponent){};
virtual ~adapterInterface()=default;
virtual void specificalInterface()
{
//do something to adapte the interface "existedProcess" in adapteeComponent
adapteeComponent->existedProcess();
}
private:
existedComponent* adapteeComponent;
};
七、桥接(bridge)
- 描述:将抽象部分(业务功能)与实现部分(平台实现)分离,是它们都可以独立地变化
- 优点:1、抽象和实现分离,拓展能力强。2、实现细节对使用者透明。
- 缺点:1、要求开发者针对抽象化进行设计与编程。
- 应用场景:1、某些类型的固有的实现逻辑,使得它们具有两个及以上的维度的变化(如一个聊天室软件,聊天业务与传输业务是不同的维度变化),这种情况下应使用桥接模式。2 、桥接模式又是类似于多继承方案,但是多继承方案往往违背了单一原则,复用性比较差。桥接模式比多继承方案更好的解决方法。
- 实现方式:
class netClass
{
public:
virtual ~netClass()=default;
virtual void send()
{
}
virtual void recv()
{
}
virtual void connect()
{
}
};
class chatRoom : public netClass
{
public:
virtual ~chatRoom()=default;
virtual void sendMessage()
{
//construct a message
netClass::send();
}
virtual void login()
{
netClass::connect();
netClass::recv();
}
};
八、装饰器(decorator)
- 描述:动态(通过组合的方式)地给一个对象增加一些额外的职责。装饰器模式比生成子(继承)更为灵活(消除重复代码和减少子类个数)。
- 优点:1、通过组合而非继承的方式,装饰器模式在实现了运行时动态拓展对象功能的能力,而且根据需要拓展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。2、可以设计出多个不同的具体装饰类,从而创造出多个不同行为的组合。
- 缺点:1、会增加很多子类,如果过度使用会使得程序变得很复杂。
- 应用场景:1、需要对现有产品增加新的功能时。2、在软件开发过程中,想使用到现存的组件但是不想改变其结构的情况下,可以动态地拓展器功能,这种情况下可以使用装饰器模式。
- 实现方式:
class baseOperate
{
public:
virtual ~baseOperate()=default;
virtual void decode()
{
}
virtual void encode()
{
}
};
class extraDriveOperate_A : public baseOperate
{
virtual ~extraDriveOperate_A();
virtual void write()
{
//extend function to construct a data stream.This part behaves the composition feature.
baseOperate::encode();
}
virtual void read()
{
baseOperate::decode();
//extend function to read the data stream.This part behaves the composition feature
}
};
class extraDriveOperate_B : public baseOperate
{
virtual ~extraDriveOperate_B();
virtual void write()
{
//extend function to construct a data stream.This part behaves the composition feature.
baseOperate::encode();
}
virtual void read()
{
baseOperate::decode();
//extend function to read the data stream.This part behaves the composition feature
}
};
九、外观(facade)
- 描述:为子系统中的一组接口提供一个一致的界面。facade模式定义了一个高层接口,这个接口使得这一子系统更加容易复用。facade模式更加注重架构的层次去看整个系统,而不是单个类的层次。facade更多是一种架构设计模式。
- 优点:1、从客户端程序来看,facade模式简化了整个组件系统的接口,对于组件内部和外部的客户程序来说,达到了一种”解耦的效果“-------内部子系统的变化不会影响到接口的变化。
- 缺点:1、不能很好地限制客户使用子类。2、增加新的子系统可能需要修改外观类或客户端的源代码,违背”开闭原则“。
- 应用场景:1、当客户端程序和各种复杂的子系统有过多的耦合的情况下,使用facade模式。
- 实现方式:
//这种思想应当体现在统一的简化接口方面,考虑到笔者的时间有限,这个例子省略了。
十、享元(flyweght)
- 描述:运用共享技术有效的支持大量细粒度的对象。
- 优点:相同对象只需要保存一份,这降低了系统中对象的数量,从而降低对系统中细粒度对象给内存带来的压力
- 缺点:1、为了使对象可以共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性。2、读取享元模式的外部状态会使得运行时间稍微变长。
- 应用场景:1、在软件系统中采用存粹的对象方案,会将大量细粒度的对象充斥在系统中,从而带来很高的内存需求方面的代价。
- 实现方式:
class memoryBlock
{
public:
virtual ~memoryBlock()=default;
memoryBlock(std::string &key):key(key){}
private:
std::string key;
};
class memoryBlockFactory
{
public:
virtual ~memoryBlockFactory()=default;
virtual memoryBlock* getMemoryBlock(std::string key)
{
memoryBlock* foundMemoryBlock = nullptr;
auto it = memoryBlockPool.find(key);
if(it == memoryBlockPool.end())
{
foundMemoryBlock = new memoryBlock(key);
memoryBlockPool.insert(std::make_pair(key, foundMemoryBlock));
}
else
{
foundMemoryBlock = it->second;
}
return foundMemoryBlock;
}
private:
std::map<std::string, memoryBlock*> memoryBlockPool;
};
十一、组合(composite)
- 描述:将对象组合成树形结构以表示“部分-整体”的层次结构。
- 优点:1、组合模式采用树型结构来实现普遍存在的对象容器,从而将“一对多”的关系转化成“一对一”关系,使得客户端程序可以一致的(复用)处理对象和对象容器。2、更容易在组合体内加入新的对象,客户端程序不会因为加入新的对象而更改源代码,满足“开闭原则”。
- 缺点:1、设计复杂,客户程序需要花费更多时间来理清类之间的层次关系。2、不容易限制容器中的构件。3、不容易使用继承的方法来增加构件的新功能。
- 应用场景:1、当客户端程序过多地依赖于对象容器复杂的内部实现结构,对象容器内部的实现结构的变化会引起客户代码的频繁变化,带来代码的维护性、拓展性等弊端时,这种情况下,应当使用组合模式。
- 实现方式:
class composite
{
public:
virtual ~composite()=default;
virtual void process()=0;
};
class parentPoint : public composite
{
public:
virtual ~parentPoint()=default;
void addElement(composite *element)
{
elements.push_back(element);
}
void removeElement(composite *element)
{
elements.remove(element);
}
void process()
{
//do something about current node
//next step is leaf node process function
for(auto &it : elements)
{
it->process();
}
}
private:
std::list<composite*> elements;
};
class leafPoint : public composite
{
public:
virtual ~leafPoint()=default;
virtual void process()
{
//do something adout this leaf point function
}
};
void treeProcess(composite &point)
{
point.process();
}
int main()
{
parentPoint root;
parentPoint treeNode1;
parentPoint treeNode2;
leafPoint leaf1Node1;
leafPoint leafNode2;
root.addElement(&treeNode1);
root.addElement(&treeNode2);
treeNode1.addElement(&leaf1Node1);
treeNode2.addElement(&leafNode2);
treeProcess(root);
}
行为型
十二、模板方法(template method)
- 描述:定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。
- 优点:1、模板模式是一种非常基础型的设计模式,它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码服用方面的基本实现结构。2、在父类中提取了公共的部分代码,便于代码复用。3、部分方法是由子类实现,子类可以通过扩展方式来增加功能,符合开闭原则。
- 缺点:1、对于每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。2、父类中的抽象方法有子类来实现,子类的执行结果会影响到父类的结果,这是一种反向的控制结构,提高了阅读代码的难度。
- 应用场景:1、在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有原因(比如框架于应用之间的关系)而无法和任务的整体结构同时实现(比如stl的容器的实现,算法与数据结构结合)。2、需要稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期需求。
- 实现方式:抽象类负责给出一个算法的轮廓和骨架,这需要定义两种类型的方法:1、模板方法: 定义了算法的骨架,按某种顺序调用其包含的基本方法。2、基本方法: 2.1、抽象方法: 在抽象类中申明,由子类实现。2.2、具体方法: 在抽象类中实现,在具体子类中可以继承或重写它。2.3、钩子方法: 在抽象类中已经实现,包括用于判断逻辑方法和需要子类重写的空方法两种。
class abstractTemplateClass
{
virtual ~abstractTemplateClass()=default;
virtual void skeletonFlow()
{
specificalMethod_A();
abstractMethod_B();
if(hookJudgeFunc_C())
{
hookMethodFunc_D();
}
}
virtual void specificalMethod_A()
{
std::cout<<"the process of specifical Method"<<std::endl;
}
virtual void abstractMethod_B()=0;
virtual bool hookJudgeFunc_C()
{
return true;
}
virtual void hookMethodFunc_D()
{
std::cout<<"the process of abstract Method"<<std::endl;
}
};
class concreteTemplateClass_example_1 : public abstractTemplateClass
{
virtual ~concreteTemplateClass()=default;
virtual void specificalMethod_A()
{
std::cout<<"the drived class object is overwriting the process of specifical Method"<<std::endl;
}
virtual void abstractMethod_B()
{
std::cout<<"the drived class object is define the process of abstract Method"<<std::endl;
}
virtual bool hookJudgeFunc_C()
{
std::cout<<"the drived class object is overwriting the judgment of hook Method"<<std::endl;
return true;
}
virtual void hookMethodFunc_D()
{
std::cout<<"the drived class object is overwriting the process of hook Method"<<std::endl;
}
};
//In next part you can define more drived class if you like.
十三、策略方法(strategy method)
- 描述:定义一系列算法,把它们封装起来,并且是它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(拓展,子类化)。
- 优点:1、策略模式及其子类为组件提供了一系列可重用的算法,从而可以使类型在运行时方便的根据需要在各个算法之间进行切换。2、多重条件语句不易维护,而使用策略模式提供了除此之外的另一种选择,这是一种解耦合的方式。3、策略模式提供相同行为的不同实现,客户端程序可以根据不同时间或空间要求选择不同的实现。4、对开闭原则的完美支持。5、策略模式把算法的使用放在环境类中,算法的实现移到具体策略类中,实现了两者的分离。
- 缺点:1、客户端程序须理解所有策略算法的区别,以便适时使用恰当的算法类。使用者的难度加大。2、策略模式会产生很多策略类。
- 应用场景:1、在软件构建过程中,某些对象使用的算法可能很多样,经常变化。
- 实现方式:
class abstrateStrategy
{
public:
virtual ~abstrateStrategy()=default;
virtual void strategyProcess()=0;
};
class specificalStrategy_A : public abstrateStrategy
{
public:
virtual ~specificalStrategy_A()=default;
virtual void strategyProcess()
{
//do something about specificalStrategy A type
}
};
class specificalStrategy_B : public abstrateStrategy
{
public:
virtual ~specificalStrategy_B()=default;
virtual void strategyProcess()
{
//do something about specificalStrategy B type
}
};
class strategyInterface
{
public:
strategyInterface():abstrateStrategyObject(nullptr) {};
virtual ~strategyInterface() {delete abstrateStrategyObject;};
virtual void givenStrategy(abstrateStrategy *ptr_strategy)
{
abstrateStrategyObject = ptr_strategy;
}
virtual void callStrategyProcess()
{
return abstrateStrategyObject->strategyProcess();
}
private:
abstrateStrategy *abstrateStrategyObject;
};
int main()
{
specificalStrategy_A *strategyObject_A = new specificalStrategy_A();
strategyInterface strategyInterface_1;
strategyInterface_1.givenStrategy(strategyObject_A);
strategyInterface_1.callStrategyProcess();
}
十四、命令方法(command method)
- 描述:将一个请求(行为)封装成一个对象,从而使你可使用不需要的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
- 优点:1、降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦。2、增加或删除命令方便,不会影响到其它类,满足“开闭原则”,对拓展比较灵活。3、可以实现宏命令。命令模式与组合模式结合,将多个命令装配成一个组合命令,这是宏命令。4、方便实现undo与redo操作。可以与备忘录模式结合,实现命令的撤销和恢复。
- 缺点:1、可能产生大量的命令的类。
- 应用场景:1、“行为请求者”与”行为实现者“呈现一种“紧耦合”。但在某些场合(需要对行为进行“记录、撤销、事务”等处理),需要恰当地处理这种变化地紧耦合。
- 实现方式:1、宏命令。命令模式与组合模式结合。
class abstractCommand
{
public:
virtual ~abstractCommand()=default;
virtual void givenCommand(std::string commandStr)=0;
virtual void commandProcess()=0;
protected:
std::string commandStr_;
};
class command_A : public abstractCommand
{
public:
command_A()=default;
command_A(string commandStr){ commandStr_ = commandStr;}
virtual ~command_A()=default;
virtual void givenCommand(std::string commandStr)
{
commandStr_ = commandStr;
}
virtual void commandProcess()
{
//do something about command A type
std::cout<< commandStr_ <<std::endl;
}
};
class command_B : public abstractCommand
{
public:
command_B()=default;
command_B(string commandStr){ commandStr_ = commandStr;}
virtual ~command_B()=default;
virtual void givenCommand(std::string commandStr)
{
commandStr_ = commandStr;
}
virtual void commandProcess()
{
//do something about command B type
std::cout<< commandStr_ <<std::endl;
}
};
class microCommand
{
public:
virtual ~microCommand()=default;
virtual void insertCommand(abstractCommand *commandNode)
{
commandList.emplace_back(commandNode);
}
virtual void microCommandProcess()
{
for(auto it : commandList)
{
it->commandProcess();
}
}
private:
std::list<abstractCommand*> commandList;
};
int main()
{
command_A *p_command_A = new command_A("command_A");
command_B *p_command_B = new command_B("command_B");
microCommand *p_microCommand = new microCommand();
p_microCommand->insertCommand(p_command_A);
p_microCommand->insertCommand(p_command_B);
p_microCommand->microCommandProcess();
}
//the example code to show the usage of memento methode is empty
十五、责任链(chain of resposibility)
- 描述:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
- 优点:1、降低了对象之间的耦合度。2、增强了系统的可拓展性。3、增强了给对象指派职责的灵活性。4、责任链简化了对象之间的链接,每个对象只需保持一个指向其后继者的引用,不需保持其它所有处理者的引用。5、责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,符合类的单一职责原则。
- 缺点:1、不能保证每个请求一定被处理。由于一个请求没有明确的接收者,该请求可能一直传到链的末端都得不到处理。2、对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。3、职责链建立的合理性要靠客户端来保证,增加了客户的复杂性,可能回由于职责链的错误设置而导致系统出错,如可能造成循环调用。4、有些过时。
- 应用场景:1、一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者或者每个对象的处理条件或权限不同,如果显示指定,将必不可少地带来发送者与接收者的紧耦合。这种情况下,可以使用责任链。
- 实现方式:
class abstractHandle
{
public:
virtual ~abstractHandle()=default;
virtual bool handleProcess(void *argv)=0;
virtual void chainRespInterface(void *argv)
{
if(handleProcess(argv) == false)
{
if(getNextHandle() != nullptr)
{
getNextHandle()->chainRespInterface(argv);
}
else
{
return;
}
}
return;
}
virtual void givenNextHandle(abstractHandle *respHandle)
{
nextResposibility = respHandle;
}
virtual abstractHandle* getNextHandle()
{
return nextResposibility;
}
protected:
abstractHandle *nextResposibility;
};
class resposibility_A : public abstractHandle
{
public:
resposibility_A(){ nextResposibility = nullptr;}
virtual ~resposibility_A()=default;
virtual bool handleProcess(void *argv)
{
//task about resposibility A
std::cout<<"now resp A process"<<std::endl;
return false;
}
};
class resposibility_B : public abstractHandle
{
public:
resposibility_B(){nextResposibility = nullptr;}
virtual ~resposibility_B()=default;
virtual bool handleProcess(void *argv)
{
//task about resposibility B
std::cout<<"now resp B process"<<std::endl;
return false;
}
};
int main()
{
resposibility_A *resp_A = new resposibility_A();
resposibility_B *resp_B = new resposibility_B();
resp_A->givenNextHandle(resp_B);
resp_A->chainRespInterface(NULL);
}
十六、状态(state)
- 描述:允许一个对象在其内部状态改变时改变它的行为,从而使对象看起来修改了其行为。
- 优点:1、状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一原则”。2、减少对象间的相互依赖,将不同状态引入到独立的对象中,会使状态转换变得更加明确,且减少对象间的相互依赖。3、有利于程序的扩展,通过定义新的子类容易增加新的状态和转换。
- 缺点:1、会增加系统的类与对象的个数。
- 应用场景:1、如果对象状态的改变,其行为也会随之变化(比如文档的状态变化,由可读变为可写状态,支持的行为完全不同)。2、一个操作中含有庞大的分支结构,并且这些分支决定对象的状态时。这些情况下,一般使用状态模式。
- 实现方式:
class stateInterfaceClass;
class concreteState_A;
class concreteState_B;
class abstractState
{
public:
virtual ~abstractState()=default;
virtual void process(stateInterfaceClass*)=0;
};
class stateInterfaceClass
{
public:
stateInterfaceClass():currentState(nullptr){}
virtual ~stateInterfaceClass()=default;
virtual void setState(abstractState *stateNode)
{
currentState.reset(stateNode);
}
virtual void startProcess()
{
currentState->process(this);
}
private:
std::shared_ptr<abstractState> currentState; //using smart point because this method can delete class object automaticaly and it is suitable at this situation.
};
class concreteState_A : public abstractState
{
public:
virtual ~concreteState_A()=default;
virtual void process(stateInterfaceClass *interfaceNode);
};
class concreteState_B : public abstractState
{
public:
virtual ~concreteState_B()=default;
virtual void process(stateInterfaceClass *interfaceNode);
};
void concreteState_A::process(stateInterfaceClass *interfaceNode)
{
//task about state A
std::cout<<"state A process"<<std::endl;
abstractState *updateState = new concreteState_B();
interfaceNode->setState(updateState);
}
void concreteState_B::process(stateInterfaceClass *interfaceNode)
{
//task about state B
std::cout<<"state B process"<<std::endl;
abstractState *updateState = new concreteState_A();
interfaceNode->setState(updateState);
}
int main()
{
concreteState_A *state_A = new concreteState_A();
stateInterfaceClass *stateInterface = new stateInterfaceClass();
stateInterface->setState(state_A);
stateInterface->startProcess(); //print A
stateInterface->startProcess(); //print B
stateInterface->startProcess(); //print A
stateInterface->startProcess(); //print B
stateInterface->startProcess(); //print A
}
十七、观察者(observer)
- 描述:定义对象间的一种一对多(变化)的依赖关系,当一个对象(subject)的状态发生变化的时候,所有依赖于它的对象都得到通知并自动更新。
- 优点:1、降低目标与观察者之间的耦合关系,两者之间是抽象耦合关系。2、目标与观察者之间建立了一套触发机制。目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播,
- 缺点:1、目标与观察者之间的依赖关系并没有解除,有可能出现循环引用。2、观察者的对象很多时,通知的发布会有很多的开销,影响程序的效率。
- 应用场景:1、当需要为某些对象建立一种“通知依赖关系”–一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都得到通知。如果这样的依赖关系过于耦合,则该软件不能很好的抵御变化。2、观察者模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分。
- 实现方式:
class abstractObSubject
{
public:
virtual ~abstractObSubject()=default;
virtual void respond()=0;
};
class observerObject
{
public:
observerObject() { observedSubject.clear();}
virtual ~observerObject()=default;
virtual void wakeSubject()
{
for(auto it : observedSubject)
{
it->respond();
}
}
virtual void addSubject(abstractObSubject *subjectNode)
{
observedSubject.emplace_back(subjectNode);
}
private:
std::list<abstractObSubject*> observedSubject;
};
class concreteObSubject_A : public abstractObSubject
{
public:
virtual ~concreteObSubject_A()=default;
virtual void respond()
{
//task about subject A
std::cout<<"observer subject A"<<std::endl;
}
};
class concreteObSubject_B : public abstractObSubject
{
public:
virtual ~concreteObSubject_B()=default;
virtual void respond()
{
//task about subject B
std::cout<<"observer subject B"<<std::endl;
}
};
int main()
{
observerObject *observer = new observerObject();
concreteObSubject_A *obSubject_A = new concreteObSubject_A();
concreteObSubject_B *obSubject_B = new concreteObSubject_B();
observer->addSubject(obSubject_A);
observer->addSubject(obSubject_B);
observer->wakeSubject();
}
十八、中介(mediator)
- 描述:用一个中介对象来封装一系列的同事对象之间的交互。中介对象使各对象不需要显式的相互引用(编译时依赖->运行时依赖),从而使其耦合松散(管理变化),并且可以独立地改变它们的交互。
- 优点:1、将多个对象间的复杂的关联关系解耦。2、将对象间的一对多(同事对象与同事对象)关系转变为一对一(同事对象与中介对象)关系,使得系统易于维护和扩展。
- 缺点:1、当同事类太多时,中介者会变得很复杂并且庞大,以至于系统难以维护。
- 应用场景:1、当对象之间存在复杂的网状结构关系而导致依赖关系混乱并且难以复用时。2、需要创建一个运行于多个类之间的对象,而不想产生新的子类的时。这些情况推荐使用中介。
- 实现方式:
class mediatorObject;
class abstractColleagueObject
{
public:
virtual ~abstractColleagueObject()=default;
virtual void registerMediator(mediatorObject *mediator)
{
givenMediator = mediator;
}
virtual void process()=0;
protected:
mediatorObject *givenMediator;
};
class concerteColleague_A : public abstractColleagueObject
{
public:
virtual ~concerteColleague_A()=default;
virtual void process();
};
class concerteColleague_B : public abstractColleagueObject
{
public:
virtual ~concerteColleague_B()=default;
virtual void process();
};
class mediatorObject
{
public:
virtual ~mediatorObject()=default;
virtual void deliverExcludeColleague(abstractColleagueObject *excludeColleague)
{
for(auto &it : colleagueList)
{
if(it != excludeColleague)
{
it->process();
}
}
}
virtual void addColleagueNode(abstractColleagueObject *colleagueNode)
{
colleagueList.emplace_back(colleagueNode);
colleagueNode->registerMediator(this);
}
protected:
std::list<abstractColleagueObject*> colleagueList;
};
void concerteColleague_A::process()
{
//task about colleague A type
std::cout<<"now colleague A process"<<std::endl;
givenMediator->deliverExcludeColleague(this);
}
void concerteColleague_B::process()
{
//task about colleague B type
std::cout<<"now colleague B process"<<std::endl;
givenMediator->deliverExcludeColleague(this);
}
int main()
{
mediatorObject *mediator = new mediatorObject();
concerteColleague_A *colleague_A = new concerteColleague_A();
concerteColleague_B *colleague_B = new concerteColleague_B();
mediator->addColleagueNode(colleague_A);
mediator->addColleagueNode(colleague_B);
colleague_A->process();
}
十九、迭代器(iterator)
- 描述:迭代器提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
- 优点:1、迭代抽象,访问一个聚合对象而无需暴露它的内部表示。2、迭代多态,为遍历不同的集合对象提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。3、增加新的聚合类和迭代器类很方便,无须修改原有代码。
- 缺点:1、对于C++来讲是过时的,现在迭代器用模板,面向对象的性能低。2、使用模板会增加类的个数,在一定程度上增加了系统的复杂度。
- 应用场景:1、STL容器等等。
- 实现方式:
template<typename T>
class iteratorClass
{
public:
iteratorClass(T value): storeValue(value){}
virtual ~iteratorClass()=default;
virtual T headNode()=0;
virtual T nextNode()=0;
virtual bool end()=0;
virtual T currentNode()=0;
protected:
T storeValue;
};
template<typename T>
class externIteratorClass : public iteratorClass<T>
{
public:
externIteratorClass(T value) : iteratorClass<T>(value){};
virtual ~externIteratorClass()=default;
virtual T headNode()
{
//You can change any thing in there.Author me choose this easiest way to show the iterator theory.
return iteratorClass<T>::storeValue;
}
virtual T nextNode()
{
//You can change any thing in there.Author me choose this easiest way to show the iterator theory.
return iteratorClass<T>::storeValue;
}
virtual bool end()
{
return 0;
}
virtual T currentNode()
{
//You can change any thing in there.Author me choose this easiest way to show the iterator theory.
return iteratorClass<T>::storeValue;
}
};
template<typename T>
class iteratorManage
{
public:
virtual ~iteratorManage()=default;
iteratorClass<T>* generateIter(T value)
{
return new externIteratorClass<T>(value);
}
};
int main()
{
iteratorManage<int> p_iterManage;
auto *it = p_iterManage.generateIter(1);
std::cout<<"this is iterator value " <<it->currentNode()<<endl;
}
二十、访问者(visitor)
- 描述:表示一个作用于某对象结构中的各元素的操作。使得在不改变(稳定)各元素的类的前提下定义(扩展)这些元素的新操作(变化)。
- 优点:1、扩展性好,在不影响对象结构的元素的情况下,为对象结构中的元素添加新功能。2、复用性好,可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。3、灵活性好,访问者模式通过所谓的双重分发来实现不更改元素类的层次结构的前提下(编译时),在运行时为类层次结构上的各个类动态添加新的操作(支持变化)。4、符合单一职责原则。访问者将相关的行为封装在一起,构成一个访问者,使得该类的功能单一。
- 缺点:1、拓展元素类成员很困难,违背开闭原则 。在访问者模式中,增加新的元素类需要在具体访问者类中增加相应的具体操作。2、违反了依赖导致原则。访问者模式依赖于具体类,而没有依赖于抽象类。
- 应用场景:1、当需求的变化,在某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样更改,会给子类带来很大的变更负担,甚至可能破坏原有的设计,这时候需要在运行时透明地为类层次结构上的各个类动态添加新的操作,这种情况使用访问者模式
- 实现方式:
class abstractVisitor;
class abstractElement
{
public:
virtual ~abstractElement()=default;
virtual void accept(abstractVisitor *)=0;
public:
//all the data menber should display to visitor
};
class abstractVisitor
{
public:
virtual ~abstractVisitor()=default;
virtual void visitElement_A(abstractElement *element)=0;
virtual void visitElement_B(abstractElement *element)=0;
};
class concreteElement_A : public abstractElement
{
public:
virtual ~concreteElement_A()=default;
virtual void accept(abstractVisitor *visitor) override
{
visitor->visitElement_A(this);
}
};
class concreteElement_B : public abstractElement
{
public:
virtual ~concreteElement_B()=default;
virtual void accept(abstractVisitor *visitor) override
{
visitor->visitElement_B(this);
}
};
class concreteVisitor : public abstractVisitor
{
public:
virtual ~concreteVisitor()=default;
virtual void visitElement_A(abstractElement *element) override
{
//visitor class will handle all the content of element A
std::cout<<"now visit element A"<<std::endl;
}
virtual void visitElement_B(abstractElement *element) override
{
//visitor class will handle all the content of element B
std::cout<<"now visit element B"<<std::endl;
}
};
int main()
{
concreteVisitor *visitor = new concreteVisitor();
concreteElement_A *element_A = new concreteElement_A();
concreteElement_B *element_B = new concreteElement_B();
element_A->accept(visitor);
element_B->accept(visitor);
}
二十一、备忘录(memento)
- 描述:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。后面可将这个对象恢复到原先保存的状态。
- 优点:1、提供一种可以恢复状态的机制。2、实现内部状态的封装,除了创建它的发起者,其它对象都不能访问这些状态信息。3、简化了发起人类的职责。发起人类不需要管理和保存其内部状态的备份,所有的状态备份放在备忘录中,并由管理者进行管理,符合单一职责原则。
- 缺点:1、内存资源消耗比较大。2、有些过时。
- 应用场景:1、在某些对象的状态转换过程中,由于某种需要,要求程序能够回溯到对象之前处于某个点的状态。同时不使用一些公开接口,避免破坏对象的封装性。这种情况下一般使用备忘录模式。
- 实现方式:
class memento
{
public:
memento(char *data):data(data){}
char* getData()
{
return data;
}
private:
char *data;
};
class mementoManager
{
public:
mementoManager():storedData(nullptr){ storedMemento.clear();}
void givenData(const char *data)
{
storedData = const_cast<char*>(data);
}
void modifyData(const char *data)
{
memento *createMemento = new memento(storedData);
storedMemento.emplace_front(createMemento);
storedData = const_cast<char*>(data);
}
void undoOperator()
{
std::list<memento*>::iterator tempMementoIter;
tempMementoIter = storedMemento.begin();
if(tempMementoIter != storedMemento.end())
{
storedData = (*tempMementoIter)->getData();
storedMemento.pop_front();
}
}
void showStoredData()
{
std::cout<<storedData<<std::endl;
}
private:
char* storedData;
std::list<memento*> storedMemento;
};
int main()
{
mementoManager *p_mementoManager = new mementoManager();
const char *storedData_A = "this is memento A";
const char *storedData_B = "this is memento B";
p_mementoManager->givenData(storedData_A);
p_mementoManager->showStoredData();
p_mementoManager->modifyData(storedData_B);
p_mementoManager->showStoredData();
p_mementoManager->undoOperator();
p_mementoManager->showStoredData();
}
二十二、解释器(interpreter)
- 描述:给定一个语言,定义它的语法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子。
- 优点:1、扩展性好,由于在解释器模式中,使用类来表示语言的语法规则,可以通过继承等机制来改变或扩展文法。2、容易实现。在语法树中的每个表达是节点都是相似的,实现其语法较为容易。
- 缺点:1、执行效率低,。在解释器模式中通常使用了大量的循环和递归。2、容易引起类的膨胀,每条规则都需要定义一个类,当包含的文法规则比较多时,类的个数会极具增加。3、可应用场景比较少。只有满足“业务规则频繁变化,且类似的结构不断重复出现,并且容易抽象为语法规则的问题”才适合使用解释器模式。
- 应用场景:满足“业务规则频繁变化,且类似的结构不断重复出现,并且容易抽象为语法规则的问题”,这时候可以使用解释器模式。
- 实现方式:
//Interpreter is hard to interpret.
//expression patternt:(1)input: a=10 (2)input:b=20 (3)input: b+a (4)output: 30
class abstractSymbolOperator;
class abstractExpression
{
public:
virtual ~abstractExpression()=default;
virtual void translateExpression(const std::string givenString)=0;
virtual void bindSymbolOperator(abstractSymbolOperator *OperatorNode);
virtual void setProcessValue(std::string &symbol, int calculatedValue) //observer mathod
{
auto it = processedValue.find(symbol);
if(it != processedValue.end())
{
it->second = calculatedValue;
return;
}
processedValue.insert(std::make_pair(symbol, calculatedValue));
}
virtual int getProcessValue(std::string &symbol) //observer mathod
{
auto it = processedValue.find(symbol);
return it->second;
}
protected:
std::map<std::string, abstractSymbolOperator*> storedOperator;
std::map<std::string, int> processedValue;
std::string operatorSymbolString;
};
class terminalExpression : public abstractExpression
{
public:
virtual ~terminalExpression()=default;
virtual void translateExpression(std::string givenString);
};
class abstractSymbolOperator
{
public:
abstractSymbolOperator(const std::string &givenSymbol): givenOperatorSymbol(givenSymbol){}
virtual ~abstractSymbolOperator()=default;
virtual int stringProcess(const std::string &givenString, abstractExpression *expressionObject) = 0;
virtual std::string& getOperatorSymbol()
{
return givenOperatorSymbol;
}
protected:
std::string givenOperatorSymbol;
};
class add_symbolOperator : public abstractSymbolOperator
{
public:
add_symbolOperator(const std::string &givenSymbol): abstractSymbolOperator(givenSymbol){}
virtual ~add_symbolOperator()=default;
virtual int stringProcess(const std::string &givenString, abstractExpression *expressionObject)
{
int occurPos = givenString.find_first_of(givenOperatorSymbol);
if(occurPos != -1 && occurPos != 0)
{
std:: string prevSymbol(givenString.substr(0, occurPos));
std:: string backSymbol(givenString.substr(occurPos + 1, givenString.size() - occurPos - 1));
std::cout<<"the result "<< (expressionObject->getProcessValue(prevSymbol) + expressionObject->getProcessValue(backSymbol))<<std::endl;
}
return false;
}
};
class equal_symbolOperator : public abstractSymbolOperator
{
public:
equal_symbolOperator(const std::string &givenSymbol): abstractSymbolOperator(givenSymbol){}
virtual ~equal_symbolOperator()=default;
virtual int stringProcess(const std::string &givenValueName, abstractExpression *expressionObject) override
{
int occurPos = givenValueName.find_first_of(givenOperatorSymbol);
if(occurPos != -1 || occurPos != 0)
{
std:: string prevSymbol((givenValueName.substr(0, occurPos)));
std:: string backSymbol((givenValueName.substr(occurPos + 1, givenValueName.size() - occurPos - 1)));
int value = std::stoi(backSymbol);
expressionObject->setProcessValue(prevSymbol, value);
return true;
}
return false;
}
};
void terminalExpression::translateExpression(const std::string givenString)
{
int operatorPos = givenString.find_first_of(operatorSymbolString);
if(operatorPos != 0 && operatorPos != -1)
{
std::string objectString(givenString, operatorPos, 1);
auto iterator = storedOperator.find(objectString);
if(iterator != storedOperator.end())
{
iterator->second->stringProcess(givenString, this);
}
}
}
void abstractExpression::bindSymbolOperator(abstractSymbolOperator *OperatorNode)
{
std::cout<<"pan "<<OperatorNode->getOperatorSymbol().c_str()<<std::endl;
auto it = storedOperator.find(OperatorNode->getOperatorSymbol());
if(it == storedOperator.end())
{
storedOperator.insert(std::make_pair(OperatorNode->getOperatorSymbol(), OperatorNode));
operatorSymbolString.append(OperatorNode->getOperatorSymbol());
}
}
int main()
{
terminalExpression *p_expression = new terminalExpression();
add_symbolOperator *p_addOperator = new add_symbolOperator(std::string("+"));
equal_symbolOperator *p_equalOperator = new equal_symbolOperator(std::string("="));
p_expression->bindSymbolOperator(p_addOperator);
p_expression->bindSymbolOperator(p_equalOperator);
p_expression->translateExpression("a=1");
p_expression->translateExpression("a+a");
}