设计模式的读书笔记
类之间的关系
-
泛化关系(继承非抽象类) SUV是汽车
-
实现关系(继承抽象类) 小汽车是车
-
聚合关系(实体对象之间的关系) 一个部门是由多个员工组成的。整体不存在,部分还存在。
-
组合关系(是一种强依赖的特殊聚合关系) 公司由多个部门组成 。整体不存在,部分也不存在了。
-
关联关系(通常是以成员变量的形式实现的)(不同类的对象之间的结构关系,是一种静态关系,一般由常识等因素决定的) 学生和学校的关系。
-
依赖关系(体现为类构造方法及类方法的传入参数)(一个对象在运行期间会用到另外一个对系的关系。是在运行期间产生的,是临时的关系) 学生和自行车的关系
创建型模式
创建型模式对类的实例化过程进行了抽象化。外界只需要知道他们的共同的接口,而不清楚其具体的实现细节。
- 简单工厂模式(4)(Simple Factory) 静态工厂方法(Static Factory Pattern)
1.1 应用场景
一个软件系统中要提供对个外观不同的按钮,(圆形按钮,方形按钮,矩形按钮),这些按钮都源自一个基类,不过不同的基类修改了部分属性。
如果我们在使用这些的按钮时候,我们不需要知道这些按钮类的名字,只需要知道该按钮类的一个参数,并提供一个实现的方法,把该参数传入方法即可返回一个对应的按钮对象.
1.2 模式结构
1.3 代码
#include "Factory.h"
#include "ConcreteProductA.h"
#include "ConcreteProductB.h"
Product* Factory::createProduct(string productname)
{
if(productname == "A")
{
return new ConcreteProductA();
}
else if(productname == "B")
{
return new ConcreteProductB();
}
return NULL;
}
1.4 模式分析
-
将对象的创建和对象本身的业务处理分理,降低耦合度。
-
工厂的方法是静态方法,使用起来方便,可以直接通过类名直接调用,只需要传入一个简单的参数,在实际的开发中,还可以将传入的参数保存在
XML等格式的配置文件中
- 工厂方法模式(5)(Factory Method)
1.1 应用场景
不在设计一个按钮工厂类来统一负责所有的产品的创建,而是将具体的按钮的创建的过程交给专门的工厂子类去完成。我们先定义一个抽象的工厂类,再定义具体的工厂类来生成圆形按钮,矩形按钮,他们实现在抽象按钮工厂类中定义的方法,
1.2 模式结构
-
Product (抽象产品)
-
ConcreteProduct(具体产品)
-
Factory(抽象工厂)
-
ConcreteFactory(具体工厂)
1.3 代码
//ConcreteFactory.cpp
#include "ConcreteFactory.h"
#include "ConcreteProduct.h"
Product* ConcreteFactory::factortMethod()
{
return new ConcreteProduct();
}
#include "Factory.h"
#include "ConcreteFactory.h"
#include "Product.h"
#include <iostream>
int main(int argc, char **argv)
{
Factory *fc = new ConcreteFactory();
Product *prod = fc->factoryMethod();
prod->use();
delete fc;
delete prod;
return 0;
}
1.4 模式分析
工厂方法模式包含四个角色:抽象产品是定义产品的接口,是工厂方法模式所创建对象的超类型,即产品对象的共同父类或接口;具体产品实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,它们之间往往一一对应;抽象工厂中声明了工厂方法,用于返回一个产品,它是工厂方法模式的核心,任何在模式中创建对象的工厂类都必须实现该接口;具体工厂是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户调用,返回一个具体产品类的实例。
工厂方法是简单工厂模式的进一步抽象和推广
- 抽象工厂模式(5)(Abstract Factory)
1.1 应用场景
在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。
抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建.当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。
1.2 模式结构
1.3 代码
#include <iostream>
#include "AbstractFactory.h"
#include "AbstractProductA.h"
#include "AbstractProductB.h"
#include "ConcreteFactory1.h"
#incldue "ConcreteFactory2.h"
int main(int argc, char **argv)
{
AbstractFactory *fc = new ConcreteFactory1();
AbstractProductA *pa = fc->createProductA();
AbstractProductB *pb = fc->createProductB();
pa->use();
pa->eat();
AbstractFactory * fc2 = new ConcreteFactory2();
AbstractProductA * pa2 = fc2->createProductA();
AbstractProductB * pb2 = fc2->createProductB();
pa2->use();
pb2->eat();
}
// ConcreteFactory1.cpp
#include "ConcreteFactory1.h"
#include "ProductA1.h"
#include "ProductB1.h"
AbstractProductA * ConcreteFactory1::createProductA(){
return new ProductA1();
}
AbstractProductB * ConcreteFactory1::createProductB(){
return new ProductB1();
}
// ProductA1.cpp
#include "ProductA1.h"
#include <iostream>
using namespace std;
void ProductA1::use(){
cout << "use Product A1" << endl;
}
1.4 模式分析
当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。
- 建造者模式(2)(Builder)
1.1 模式场景
在软件开发中,存在大量类似汽车一样的复杂对象,它们拥有一系列成员属性,这些成员属性中有些是引用类型的成员对象。而且在这些复杂对象中,还可能存在一些限制条件,如某些属性没有赋值则复杂对象不能作为一个完整的产品使用;有些属性的赋值必须按照某个顺序,一个属性没有赋值之前,另一个属性可能无法赋值等。
复杂对象相当于一辆有待建造的汽车,而对象的属性相当于汽车的部件,建造产品的过程就相当于组合部件的过程。由于组合部件的过程很复杂,因此,这些部件的组合过程往往被“外部化”到一个称作建造者的对象里,建造者返还给客户端的是一个已经建造完毕的完整产品对象,而用户无须关心该对象所包含的属性以及它们的组装方式,这就是建造者模式的模式动机。
1.2 模式结构
1.3 代码
#include <iostream>
#include "Builder.h"
#include "Director.h"
#include "Product.h"
#include "ConcreteBuilder.h"
int main(int argc, char **argv)
{
ConcreteBuilder *builder = new ConcreteBuilder();
Director director;
director.setBuilder(builder);
Product* pd = director.construct();
pd->show();
delete builder;
delete pd;
return 0;
}
//ConcreteBuilder.cpp
#include "ConcreteBuilder.h"
ConcreteBuilder::ConcreteBuilder()
{
}
ConcreteBuilder::~ConcreteBuilder()
{
}
void ConcreteBuilder::buildPartA()
{
m_prod->setA("A style");
}
void ConcreteBuilder::buildPartB()
{
m_prod->setA("B style");
}
Product* ConcreteBuilder::getResult()
{
return m_product;
}
//Director.cpp
#include "Director.h"
Director::Director()
{
}
void Director::setBuilder(Builder *builder)
{
m_builder = builder;
}
Product* Director::construct()
{
m_builder->buildPartA();
m_builder->buildPartB();
return m->builder->getResult();
}
1.4 实例
建造者模式用于描述KFC是如何创建套餐的,套餐是一个复杂的对象,包括主食(汉堡,鸡翅)和饮料等组成部分。KFC服务员根据客户的不同要求构造不同的套餐
在很多游戏软件中,地图包括天空、地面、背景等组成部分,人物角色包括人体、服装、装备等组成部分,可以使用建造者模式对其进行设计,通过不同的具体建造者创建不同类型的地图或人物。
- 单例模式(4)(Singelton)
1.1 模式场景
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。
在单例模式的实现过程中,需要注意如下三点:
- 单例类的构造函数为私有;
- 提供一个自身的静态私有成员变量;
- 提供一个公有的静态工厂方法。
1.2 模式结构
1.3 代码
#include <iostream>
#include "Singleton.h"
int main(int argc ,char **argv)
{
Singleton *singleton = Singleton::getInstance();
singleton->singleOperation();
}
//Singleton.cpp
#include "Singleton.h"
//static
Singleton* Singleton::p_instance = NULL;
//private
Singleton::Singleton()
{
}
Singleton::~Singleton()
{
delete p_instance;
}
//static
Singleton::getInstance()
{
if(p_instance == NULL)
p_instance = new Singleton();
return p_instance;
}
void Singleton::singleOperation()
{
std::cout << "Single operation";
}
1.4 模式分析
滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如果实例化的对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致对象状态的丢失。
结构性模式
结构性模式描述如何将类或者对象结合在一起形成更大的结构,就像搭积木一样.
-
类结构型模式(一般只存在继承关系和实现关系),由多个类组合成一个更大的系统
-
对象结构型模式(通过关联关系在一个类中定义另一个类的实例对象)
- 适配器模式(4)
1.1 应用场景
通常情况下,客户端可以通过目标类的接口访问它所提供的服务。有时,现有的类可以满足客户类的功能需要,但是它所提供的接口不一定是客户类所期望的,这可能是因为现有类中方法名与目标类中定义的方法名不一致等原因所导致的。
在适配器模式中可以定义一个包装类,包装不兼容接口的对象,这个包装类指的就是适配器(Adapter),它所包装的对象就是适配者(Adaptee),即被适配的类。
适配器提供客户类需要的接口,适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器可以使由于接口不兼容而不能交互的类可以一起工作。这就是适配器模式的模式动机。
1.2 模式结构
1.3 代码
#include "Adapter.h"
#include "Adaptee.h"
#include "Target.h"
#include <iostream>
int main(int argc, char **argv)
{
Adaptee *adaptee = new Adaptee();
Target *tar = new Adapter(adaptee);
tar->request();
return 0;
}
//Adapter.h
#include "Target.h"
#include "Adaptee.h"
class Adapter: public Target
{
public:
Adapter(Adaptee* adaptee);
virtual ~Adapter();
virtual void request();
private:
Adaptee *adaptee_;
};
//Adapter.cpp
#include "Adapter.h"
Adapter::Adapter(Adaptee* adaptee)
{
adaptee_ = adaptee;
}
Adapter::~Adapter()
{
}
void Adapter::request()
{
adaptee_->specifcRequest();
}
//Adaptee.h
class Adaptee
{
public:
Adaptee();
virtual ~Adaptee();
void specifcRequest();
};
1.4 实例
Sun公司在1996年公开了Java语言的数据库连接工具JDBC,JDBC使得Java语言程序能够与数据库连接,并使用SQL语言来查询和操作数据。JDBC给出一个客户端通用的抽象接口,每一个具体数据库引擎(如SQL Server、Oracle、MySQL等)的JDBC驱动软件都是一个介于JDBC接口和数据库引擎接口之间的适配器软件。抽象的JDBC接口和各个数据库引擎API之间都需要相应的适配器软件,这就是为各个不同数据库引擎准备的驱动程序。
1.5 总结
适配器者类实现了目标抽象类接口并继承了适配者类
适配器模式适用情况包括:系统需要使用现有的类,而这些类的接口不符合系统的需要;想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类一起工作。
- 桥接模式(3)
1.1 应用场景
设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有如下两种设计方案:
- 第一种设计方案是为每一种形状都提供一套各种颜色的版本。
- 第二种设计方案是根据实际需要对形状和颜色进行组合
对于有两个变化维度(即两个变化的原因)的系统,采用方案二来进行设计系统中类的个数更少,且系统扩展更为方便。设计方案二即是桥接模式的应用。桥接模式将继承关系转换为关联关系,从而降低了类与类之间的耦合,减少了代码编写量。
1.2 模式结构
1.3 代码
#include <iostream>
#include "ConcreteImplementorA.h"
#include "ConcreteImplementorB.h"
#include "Abstraction.h"
#include "RefinedAbstraction.h"
int main(int argc ,char **argv)
{
Implementor *pImp = new ConcreteImplementorA();
Abstraction *pa = new RefinedAbstraction(pImp);
pa->operation();
Abstraction *pb = new RefinedAbstraction(new ConcreteImplementorB());
pb->operation();
delete pa;
delete pb;
return 0;
}
//RefinedAbstraction.h
#include "Abstraction.h"
class RefinedAbstraction: public Abstraction
{
public:
RefinedAbstraction();
RefinedAbstraction(Implementor* imp);
virtual ~RefinedAbstraction();
virtual void operation();
private:
Implementor *imp_;
}
//RefinedAbstraction.cpp
#include "RefinedAbstraction.h"
#include <iostream>
using namespace std;
RefinedAbstraction::RefinedAbstraction(){
}
RefinedAbstraction::RefinedAbstraction(Implementor* imp)
:Abstraction(imp)
{
imp_ = imp;
}
RefinedAbstraction::~RefinedAbstraction(){
}
void RefinedAbstraction::operation(){
cout << "do something else ,and then " << endl;
imp_->operationImp();
}
1.4 实例
如果需要开发一个跨平台视频播放器,可以在不同操作系统平台(如Windows、Linux、Unix等)上播放多种格式的视频文件,常见的视频格式包括MPEG、RMVB、AVI、WMV等。现使用桥接模式设计该播放器。
一个Java桌面软件总是带有所在操作系统的视感(LookAndFeel),如果一个Java软件是在Unix系统上开发的,那么开发人员看到的是Motif用户界面的视感;在Windows上面使用这个系统的用户看到的是Windows用户界面的视感;而一个在Macintosh上面使用的用户看到的则是Macintosh用户界面的视感,Java语言是通过所谓的Peer架构做到这一点的。Java为AWT中的每一个GUI构件都提供了一个Peer构件,在AWT中的Peer架构就使用了桥接模式
1.5 总结
桥接模式包含如下四个角色:抽象类中定义了一个实现类接口类型的对象并可以维护该对象;扩充抽象类扩充由抽象类定义的接口,它实现了在抽象类中定义的抽象业务方法,在扩充抽象类中可以调用在实现类接口中定义的业务方法;实现类接口定义了实现类的接口,实现类接口仅提供基本操作,而抽象类定义的接口可能会做更多更复杂的操作;具体实现类实现了实现类接口并且具体实现它,在不同的具体实现类中提供基本操作的不同实现,在程序运行时,具体实现类对象将替换其父类对象,提供给客户端具体的业务操作方法。
- 装饰器模式(3)
1.1 应用场景
一般有两种方式可以实现给一个类或对象增加行为:
-
继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。
-
关联机制,即将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为以便扩展自己的行为,我们称这个嵌入的对象为装饰器(Decorator)
1.2 模式结构
装饰器模式有如下几个角色:
:
- Component: 抽象构件
- ConcreteComponent: 具体构件
- Decorator: 抽象装饰类
- ConcreteDecorator: 具体装饰类
1.3 代码
//ConcreteaComponent.cpp
#include "ConcreteComponent.h"
ConcreteComponent::ConcreteComponent()
{
}
ConcreteComponent::~ConcreteComponent()
{
}
void ConcreteComponent::operation()
{
cout << " ConcreteComponent normal operation!" <<endl;
}
//ConcreteDeacoratorA.h
#include "Decorator.h"
#include "Component.h"
class ConcreteDecoratorA : public Decorator
{
public:
ConcreteDecoratorA(Component *comp);
virtual ~ConcreteDecoratorA();
void addBehavior();
virtual void operation();
}
#include "ConcreteDecoratorA.h"
ConcreteDecoratorA::ConcreteDecoratorA(Component* pcmp)
:Decorator(pcmp)
{
}
ConcreteDecoratorA::~ConcreteDecoratorA(){
}
void ConcreteDecoratorA::addBehavior(){
cout << "addBehavior AAAA" << endl;
}
void ConcreteDecoratorA::operation(){
Decorator::operation();
addBehavior();
}
1.4 总结
装饰模式包含四个角色:抽象构件定义了对象的接口,可以给这些对象动态增加职责(方法);具体构件定义了具体的构件对象,实现了 在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法);
抽象装饰类是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现;具体装饰类是抽象装饰类的子类,负责向构件添加新的职责。
- 外观模式(5)
1.1 应用场景
外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。
1.2 模式结构
1.3 代码
#include <iostream>
#include "Facade.h"
using namespace std;
int main(int argc, char *argv[])
{
Facade fa;
fa.wrapOpration();
return 0;
}
//Facade.h
#include "SystemC.h"
#include "SystemA.h"
#include "SystemB.h"
class Facade
{
public:
Facade();
virtual ~Facade();
void wrapOpration();
private:
SystemC *m_SystemC;
SystemA *m_SystemA;
SystemB *m_SystemB;
};
//Facade.cpp
#include "Facade.h"
Facade::Facade(){
m_SystemA = new SystemA();
m_SystemB = new SystemB();
m_SystemC = new SystemC();
}
Facade::~Facade(){
delete m_SystemA;
delete m_SystemB;
delete m_SystemC;
}
void Facade::wrapOpration(){
m_SystemA->operationA();
m_SystemB->operationB();
m_SystemC->opeartionC();
}
- 享元模式(1)
1.1 应用场景
1.2 模式结构
1.3 代码
#include "FlyweightFactory.h"
#include "Flywight.h"
#include "ConcreteFlyweight.h"
#include <iostream>
int main(int argc, char **argv)
{
FlyweightFactory factory;
Flyweight * fw1 = factory.getFlyweight("one");
fw1->operation();
Flyweight * fw2 = factory.getFlyweight("two");
fw2->operation();
Flyweight * fw3 = factory.getFlyweight("one");
fw3->operation();
return 0;
}
//FlyweightFactory.cpp
#include "FlyweightFactory.h"
#include "ConcreteFlyweight.h"
FlyweightFactory::FlyweightFactory()
{
}
FlyweightFactory::~FlyweightFactory()
{
}
Flyweight* FlyweightFactory::getFlyweight(string str)
{
map<string ,Flyweight*>::iterator it = flyweightFactory_.find(str);
if(it == flyweightFactory_.end())
{
Flyweight *fw = new ConcreteFlyweight();
flyweightFactory_.insert(make_pair(str,fw));
return fw;
}
else
{
cout << "already exist in the pool, use the exist one";
return it->second;
}
}
//ConcreteFlyweight.h
#include "Flyweight.h"
#include <string>
using namespace std;
class ConcreteFlyweight : public Flyweight
{
public:
ConcreteFlyweight(string str);
virtual ~ConcreteFlyweight();
virtual void operation();
private:
string intrinsicState;
};
//ConcreteFlyweight.cpp
#include "ConcreteFlyweight.h"
#include <iostream>
using namespace std;
ConcreteFlyweight::ConcreteFlyweight(string str){
intrinsicState = str;
}
ConcreteFlyweight::~ConcreteFlyweight(){
}
void ConcreteFlyweight::operation(){
cout << "Flyweight[" << intrinsicState << "] do operation." << endl;
}
1.4 实例
享元模式在编辑器软件中大量使用,如在一个文档中多次出现相同的图片,则只需要创建一个图片对象,通过在应用程序中设置该图片出现的位置,可以实现该图片在不同地方多次重复显示。
- 代理模式(4)
1.1 应用场景
在某些情况下,一个客户不想或者不能直接引用一个对 象,此时可以通过一个称之为“代理”的第三者来实现 间接引用。代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。
通过引入一个新的对象(如小图片和远程代理 对象)来实现对真实对象的操作或者将新的对 象作为真实对象的一个替身,这种实现机制即 为代理模式,通过引入代理对象来间接访问一 个对象,这就是代理模式的模式动机
给某一个对象提供一个代 理,并由代理对象控制对原对象的引用
1.2 模式结构
1.3 代码
#include "Proxy.h"
#include <iostream>
int main(int argc , char **argv)
{
Proxy proxy;
proxy.request();
return 0;
}
//Proxy.h
#include "Subject.h"
#include "RealSubject.h"
class Proxy: public Subject
{
public:
Proxy();
virtual ~Proxy();
void request();
private:
void afterRequest();
void preRequest();
RealSubject *m_pRealSubject;
};
//Proxy.cpp
#include "Proxy.h"
Proxy::Proxy()
{
m_pRealSubject = new RealSubject();
}
Proxy::~Proxy()
{
delete m_pRealSubject;
}
void Proxy::afterRequest(){
cout << "Proxy::afterRequest" << endl;
}
void Proxy::preRequest(){
cout << "Proxy::preRequest" << endl;
}
void Proxy::request()
{
preRequest();
m_pRealSubject->request();
afterRequest();
}
1.4 试用环境
-
远程(Remote)代理:为一个位于不同的地址空间的对象提供一个本地 的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在 另一台主机中,远程代理又叫做大使(Ambassador)。
-
虚拟(Virtual)代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
-
Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟 到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个 开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。
-
保护(Protect or Access)代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
-
缓冲(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
-
防火墙(Firewall)代理:保护目标不让恶意用户接近。
-
同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
-
智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。
1.5 模式应用
EJB、Web Service等分布式技术都是代理模式的应用。在EJB中使用了RMI机制,远程服务器中的企业级Bean在本地有一个桩代理,客户端通过桩来调用远程对象中定义的方法,而无须直接与远程对象交互。在EJB的使用中需要提供一个公共的接口,客户端针对该接口进行编程,无须知道桩以及远程EJB的实现细节。
行为型模式
行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。
行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。
-
类行为型模式:类的行为型模式使用继承关系在几个类之间分配行为,类行为型模式主要通过多态等方式来分配父类与子类的职责。
-
对象行为型模式:对象的行为型模式则使用对象的聚合关联关系来分配行为,对象行为型模式主要是通过对象关联等方式来分配两个或多个类的职责。根据“合成复用原则”,系统中要尽量使用关联关系来取代继承关系,因此大部分行为型设计模式都属于对象行为型设计模式。
- 命令模式(4)
1.1 模式定义
将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
1.2 模式结构
1.3 代码
#include "ConcreteCommand.h"
#include "Invoker.h"
#include "Receiver.h"
int main(int argc, char **argv)
{
Receiver *pReceiver = new Receiver();
ConcreteCommand *pCommand = new ConcreteCommand(pReceiver);
Invoker *pInvoker = new Invoker(pCommand);
pInvoker->call();
delete pReceuiver;
delete pCommand;
delete pInvoker;
return 0;
}
//Receiver.h
#include ""
class Receiver{
public:
Receiver();
~Receiver();
void action();
};
//Receiver.cpp
#include "Receiver.h"
#include <iostream>
using namespace std;
Receiver::Receiver(){
}
Receiver::~Receiver(){
}
void Receiver::action(){
cout << "receiver action." << endl;
}
//ConcreteCommand.h
#include "Command.h"
#include "Receiver.h"
class ConcreteCommand : public Command
{
public:
ConcreteCommand(Receiver * pReceiver);
virtual ~ConcreteCommand();
virtual void execute();
private:
Receiver *m_pReceiver;
};
//ConcreteCommand.cpp
#include "ConcreteCommand.h"
#include <iostream>
using namespace std;
ConcreteCommand::ConcreteCommand(Receiver *pReceiver){
m_pReceiver = pReceiver;
}
ConcreteCommand::~ConcreteCommand(){
}
void ConcreteCommand::execute(){
cout << "ConcreteCommand::execute" << endl;
m_pReceiver->action();
}
//Invoker.h
#inclued "Command.h"
class Invoker{
public:
Invoker(Command*);
~Invoker();
void call();
private:
Command *pCommand_;
};
//Invoker.cpp
#include "Invoker.h"
#include <iostream>
using namespace std;
Invoker::Invoker(Command * pCommand){
m_pCommand = pCommand;
}
Invoker::~Invoker(){
}
void Invoker::call(){
cout << "invoker calling" << endl;
m_pCommand->execute();
}
1.4 模式分析
命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
1.5 实例
电视机是请求的接收者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应电视机的不同操作。抽象命令角色由一个命令接口来扮演,有三个具体的命令类实现了抽象命令接口,这三个具体命令类分别代表三种操作:打开电视机、关闭电视机和切换频道。显然,电视机遥控器就是一个典型的命令模式应用实例。
1.6 总结
命令模式包含四个角色:抽象命令类中声明了用于执行请求的execute()
等方法,通过这些方法可以调用请求接收者的相关操作;具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中;调用者即请求的发送者,又称为请求者,它通过命令对象来执行请求;接收者执行与请求相关的操作,它具体实现对请求的业务处理。
- 中介者模式(2)
1.1 模式动机
+ 在用户与用户直接聊天的设计方案中,用户对象之间存在很强的关联性,将导致系统出现如下问题:
+ 系统结构复杂:对象之间存在大量的相互关联和调用,若有一个对象发生变化,则需要跟踪和该对象关联的其他所有对象,并进行适当处理。
+ 对象可重用性差:由于一个对象和其他对象具有很强的关联,若没有其他对象的支持,一个对象很难被另一个系统或模块重用,这些对象表现出来更像一个不可分割的整体,职责较为混乱。
1.2 模式结构
1.3 代码
#include "ConcreteMeditor.h"
#include "ConcreteColleagueA.h"
#include "ConcreteColleagueB.h"
#include "iostream"
int main(int argc, char **argv)
{
ConcreteColleagueA * pa = new ConcreteColleagueA();
ConcreteColleagueB * pb = new ConcreteColleagueB();
ConcreteMediator * pm = new ConcreteMediator();
pm->registered(1,pa);
pm->registered(2,pb);
pa->sendmsg(2,"hello,i am a");
// sendmsg from b to a
pb->sendmsg(1,"hello,i am b");
delete pa,pb,pm;
return 0;
}
//ConcreteMediator.h
#include "ConcreteColleagueB.h"
#include "Mediator.h"
#include "ConcreteColleagueA.h"
#include <map>
using namespace std;
class ConcreteMediator : public Mediator
{
public:
ConcreteMediator();
virtual ~ConcreteMediator();
virtual void operation(int nWho,string str);
virtual void registered(int nWho, Colleague * aColleague);
private:
map<int,Colleague*> m_mpColleague;
};
#include "ConcreteMediator.h"
#include <map>
#include <iostream>
using namespace std;
ConcreteMediator::ConcreteMediator(){
});
ConcreteMediator::~ConcreteMediator(){
}
void ConcreteMediator::operation(int nWho,string str){
map<int,Colleague*>::const_iterator itr = m_mpColleague.find(nWho);
if(itr == m_mpColleague.end())
{
cout << "not found this colleague!" << endl;
return;
}
Colleague* pc = itr->second;
pc->receivemsg(str);
}
void ConcreteMediator::registered(int nWho,Colleague * aColleague){
map<int,Colleague*>::const_iterator itr = m_mpColleague.find(nWho);
if(itr == m_mpColleague.end())
{
m_mpColleague.insert(make_pair(nWho,aColleague));
//同时将中介类暴露给colleague
aColleague->setMediator(this);
}
}
//ConcreteColleagueA.h
#include "Colleague.h"
class ConcreteColleagueA : public Colleague
{
public:
ConcreteColleagueA();
virtual ~ConcreteColleagueA();
virtual void sendmsg(int toWho,string str);
virtual void receivemsg(string str);
};
#include "ConcreteColleagueA.h"
#include <iostream>
using namespace std;
ConcreteColleagueA::ConcreteColleagueA(){
}
ConcreteColleagueA::~ConcreteColleagueA(){
}
void ConcreteColleagueA::sendmsg(int toWho,string str){
cout << "send msg from colleagueA,to:" << toWho << endl;
m_pMediator->operation(toWho,str);
}
void ConcreteColleagueA::receivemsg(string str){
cout << "ConcreteColleagueA reveivemsg:" << str <<endl;
}
1.4 实例
某论坛系统欲增加一个虚拟聊天室,允许论坛会员通过该聊天室进行信息交流,普通会员(CommonMember)可以给其他会员发送文本信息,钻石会员(DiamondMember)既可以给其他会员发送文本信息,还可以发送图片信息。该聊天室可以对不雅字符进行过滤,如“日”等字符;还可以对发送的图片大小进行控制。用中介者模式设计该虚拟聊天室。
- 观察者模式(5)
1.1 模式定义
建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展,这就是观察者模式的模式动机。
1.2 模式结构
1.3 代码
#include "Subject.h"
#include "ConcreteObserver.h"
#include "ConcreteSubject.h"
#include <iostream>
int main(int argc ,char **argv)
{
ConcreteObserver *observer1 = new ConcreteObserver("A");
ConcreteObserver *observer2 = new ConcreteObserver("B");
ConcreteSubject *subject = new ConcreteSubjct();
subject->attach(observer1);
subject->attach(observer2);
subject->set_state(2);
subject->notify();
subject->detach(observer1);
subject->set_state(1);
subject->notify();
del observer1;
del observer2;
del subject;
return 0;
}
//Subject.h
#include "Observer.h"
#include <vector>
class Subject {
public:
Subject();
virtual ~Subject();
void attach(Observer *);
void detach(Observer *);
void notify();
virtual int getState() =0;
virtual void setState(int i) = 0;
private:
vector<Observer*> vtObj_;
};
//Subject.cpp
#include "Subject.h"
Subject::Subject()
{
}
Subject::~Subject()
{
}
void Subject::attach(Observer* observer)
{
vtObj_.push_back(observer);
}
void Subject::detach(Observer *observer)
{
for(vector<Observer*>::iterator it = vtObj_.begin(); it != vtObj_.end();it++)
{
if(it == observer)
{
vtObj_.earse(it)
return;
}
}
}
void Subject::notify(){
for(vector<Obeserver*>::iterator itr = vtObj_.begin();
itr != vtObj_.end();
itr++)
{
(*itr)->update(this);
}
}
//Observer.h
#include "Subject.h"
class Observer{
public:
Observer();
virtual ~Observer();
virtual void update(Subject* subj) = 0 ;
};
#include <string>
using namespace std;
//ConcreteObserver.h
class ConcreteObserver: public Observer{
public:
ConcreteObserver(string name);
virtual ~ConcreteObserver();
virtual void update(Subject* subj);
private:
string objname_;
int observerState_;
};
#include "ConcreteObeserver.h"
#include <iostream>
#include <vector>
#include "Subject.h"
using namespace std;
ConcreteObeserver::ConcreteObeserver(string name){
objname_ = name;
}
ConcreteObeserver::~ConcreteObeserver(){
}
void ConcreteObeserver::update(Subject * sub){
observerState_ = sub->getState();
cout << "update oberserver[" << objname_ << "] state:" << obeserverState_ << endl;
}
1.4 总结
观察者模式定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅模式、模型-视图模式、源-监听器模式或从属者模式。观察者模式是一种对象行为型模式。
- 状态模式(3)
1.1 模式定义
在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。
1.2 模式结构
1.3 代码
#include <iostream>
#include "ConcreteStateA.h"
#include "ConcreteStateB.h"
#include "Context.h"
int main(int argc ,char **argv)
{
char a = '0';
if('0' == a)
cout << "yes" << endl;
else
cout << "no" << endl;
Context *context = new Context();
context->request();
context->request();
context->request();
del context;
return 0;
}
//Context.h
#include "State.h"
class Context{
public:
Context();
virtual Context();
void request();
void changeState(State*);
private:
State state_;
};
#include "Context.h"
Context::Context()
{
state_ = ConcreteStateA::Instance();
}
Context::~Context()
{}
void Context::request()
{
state_->handle(this);
}
void Context::changeState(State* state)
{
state_ = state;
}
//ConcreteStateA.h
class ConcreteStateA :public State{
public:
virtual ~ConcreteState();
static State* Instance();
void handle(Context* context);
private:
State* state_;
ConcreteStateA();
};
#include "ConcreteStateA.h"
#include "ConcreteStateB.h"
#include "Context.h"
#include <iostream>
using namespace std;
State * ConcreteStateA::m_pState = NULL;
ConcreteStateA::ConcreteStateA(){
}
ConcreteStateA::~ConcreteStateA(){
}
State * ConcreteStateA::Instance()
{
if ( NULL == state_)
{
state_ = new ConcreteStateA();
}
return state_;
}
void ConcreteStateA::handle(Context * c){
cout << "doing something in State A.\n done,change state to B" << endl;
c->changeState(ConcreteStateB::Instance());
}
1.4 实例
这个示例来自《设计模式》,展示了一个简化版的TCP协议实现; TCP连接的状态有多种可能,状态之间的转换有相应的逻辑前提。
状态模式在工作流或游戏等类型的软件中得以广泛使用,甚至可以用于这些系统的核心功能设计,如在政府OA办公系统中,一个批文的状态有多种:尚未办理;正在办理;正在批示;正在审核;已经完成等各种状态,而且批文状态不同时对批文的操作也有所差异。使用状态模式可以描述工作流对象(如批文)的状态转换以及不同状态下它所具有的行为。
- 策略模式(4)
1.1 模式定义
完成一项任务,往往可以有多种不同的方式,每一种方式称为一个策略,我们可以根据环境或者条件的不同选择不同的策略来完成该项任务。
为了解决这些问题,可以定义一些独立的类来封装不同的算法,每一个类封装一个具体的算法,在这里,每一个封装算法的类我们都可以称之为策略(Strategy),为了保证这些策略的一致性,一般会用一个抽象的策略类来做算法的定义,而具体每种算法则对应于一个具体策略类。
1.2 模式结构
1.3 代码
#include <iostream>
#include "Context.h"
#include "ConcreteStrategyA.h"
#include "ConcreteStrategyB.h"
#include "Strategy.h"
#include <vector>
using namespace std;
int main(int argc, char *argv[])
{
Strategy * s1 = new ConcreteStrategyA();
Context * cxt = new Context();
cxt->setStrategy(s1);
cxt->algorithm();
Strategy *s2 = new ConcreteStrategyB();
cxt->setStrategy(s2);
cxt->algorithm();
delete s1;
delete s2;
return 0;
}
// Context.h
#include "Strategy.h"
class Context
{
public:
Context();
virtual ~Context();
void algorithm();
void setStrategy(Strategy* st);
private:
Strategy *m_pStrategy;
};
// Context.cpp
#include "Context.h"
Context::Context(){
}
Context::~Context(){
}
void Context::algorithm(){
m_pStrategy->algorithm();
}
void Context::setStrategy(Strategy* st){
m_pStrategy = st;
}
// ConcreteStrategyA.h
#include "Strategy.h"
class ConcreteStrategyA : public Strategy
{
public:
ConcreteStrategyA();
virtual ~ConcreteStrategyA();
virtual void algorithm();
};
// ConcreteStrategyA.cpp
#include "ConcreteStrategyA.h"
#include <iostream>
using namespace std;
ConcreteStrategyA::ConcreteStrategyA(){
}
ConcreteStrategyA::~ConcreteStrategyA(){
}
void ConcreteStrategyA::algorithm(){
cout << "use algorithm A" << endl;
}