设计模式23
设计模式23
诡隐沦设计模式六大原则
1、开闭原则(Open Close Principle)
开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
3、依赖倒转原则(Dependence Inversion Principle)
这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
5、迪米特法则,又称最少知道原则(Demeter Principle)
最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。
开闭原则:实现热插拔,提高扩展性。
里氏代换原则:实现抽象的规范,实现子父类互相替换;
依赖倒转原则:针对接口编程,实现开闭原则的基础;
接口隔离原则:降低耦合度,接口单独设计,互相隔离;
迪米特法则,又称不知道原则:功能模块尽量独立;
合成复用原则:尽量使用聚合,组合,而不是继承;
问题
多态与里氏替换原则是否冲突?
里氏替换原则要求特殊性不可违背普遍性,这个违背是指子类修改父类。而多态是指子类本身就父类中的普遍性进行特殊化的继承,实际上并未修改父类。所以,两者不冲突,是一种补充关系。多态使得父类的普遍性能够在子类中进行特殊化继承。里氏代换原则要求继承关系必须符合普遍性与特殊性的规律。
创建型模式
工厂模式(Factory Pattern)
enum CTYPE {COREA, COREB}; |
抽象工厂模式(Abstract Factory Pattern)
//3.抽象工厂模式
//工厂
class CoreFactory
{
public:
virtual SingleCore* CreateSingleCore() = 0;
virtual MultiCore* CreateMultiCore() = 0;
};
//工厂A,专门用来生产A型号的处理器
class FactoryA :public CoreFactory
{
public:
SingleCore* CreateSingleCore() { return new SingleCoreA(); }
MultiCore* CreateMultiCore() { return new MultiCoreA(); }
};
//工厂B,专门用来生产B型号的处理器
class FactoryB : public CoreFactory
{
public:
SingleCore* CreateSingleCore() { return new SingleCoreB(); }
MultiCore* CreateMultiCore() { return new MultiCoreB(); }
};
区别:工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个
单例模式(Singleton Pattern)
//Singleton.h
class Singleton
{
public:
static Singleton* GetInstance();
void DeleteInstance();
private:
Singleton() {}
static Singleton *singleton;
};
//Singleton.cpp
Singleton* Singleton::singleton = NULL;
Singleton* Singleton::GetInstance()
{
if(singleton == NULL)
singleton = new Singleton();
//singleton = new(std::nothrow) Singleton();
//在内存不足时,new (std::nothrow)并不抛出异常,而是将指针置NULL
return singleton;
}
void Singleton::DeleteInstance(){
if (m_Instance!=NULL)
{
delete m_Instance;
m_Instance = NULL;
}
}
建造者模式(Builder Pattern)
class Builder
{
public:
virtual void BuildHead() {}
virtual void BuildBody() {}
virtual void BuildLeftArm(){}
virtual void BuildRightArm() {}
virtual void BuildLeftLeg() {}
virtual void BuildRightLeg() {}
};
//构造瘦人
class ThinBuilder : public Builder
{
public:
void BuildHead() { cout\<\<”build thin body”\<\<endl; }
void BuildBody() { cout\<\<”build thin head”\<\<endl; }
void BuildLeftArm() { cout\<\<”build thin leftarm”\<\<endl; }
void BuildRightArm() { cout\<\<”build thin rightarm”\<\<endl; }
void BuildLeftLeg() { cout\<\<”build thin leftleg”\<\<endl; }
void BuildRightLeg() { cout\<\<”build thin rightleg”\<\<endl; }
};
//构造胖人
class FatBuilder : public Builder
{
public:
void BuildHead() { cout\<\<”build fat body”\<\<endl; }
void BuildBody() { cout\<\<”build fat head”\<\<endl; }
void BuildLeftArm() { cout\<\<”build fat leftarm”\<\<endl; }
void BuildRightArm() { cout\<\<”build fat rightarm”\<\<endl; }
void BuildLeftLeg() { cout\<\<”build fat leftleg”\<\<endl; }
void BuildRightLeg() { cout\<\<”build fat rightleg”\<\<endl; }
};
//构造的指挥官
class Director
{
private:
Builder *m_pBuilder;
public:
Director(Builder *builder) { m_pBuilder = builder; }
void Create(){
m_pBuilder->BuildHead();
m_pBuilder->BuildBody();
m_pBuilder->BuildLeftArm();
m_pBuilder->BuildRightArm();
m_pBuilder->BuildLeftLeg();
m_pBuilder->BuildRightLeg();
}
};
int main() int main()
{
FatBuilder thin;
Director director(&thin);
director.Create();
return 0;
}
原型模式(Prototype Pattern)
//实现的关键就是实现Clone函数,对于C++来说,其实就是拷贝构造函数
//父类
class Resume
{
protected:
char *name;
public:
Resume() {}
virtual ~Resume() {}
virtual Resume* Clone() { return NULL; }
virtual void Set(char *n) {}
virtual void Show() {}
};
class ResumeA : public Resume
{
public:
ResumeA(const char *str); //构造函数
ResumeA(const ResumeA \&r); //拷贝构造函数
~ResumeA(); //析构函数
ResumeA* Clone(); //克隆,关键所在
void Show(); //显示内容
};
ResumeA::ResumeA(const char *str)
{
if(str == NULL) {
name = new char[1];
name[0] = ‘\0’;
}
else {
name = new char[strlen(str)+1];
strcpy(name, str);
}
}
ResumeA::~ResumeA() { delete [] name;}
ResumeA::ResumeA(const ResumeA \&r) {
name = new char[strlen(r.name)+1];
strcpy(name, r.name);
}
ResumeA* ResumeA::Clone() {
return new ResumeA(*this);
}
void ResumeA::Show() {
cout\<\<”ResumeA name : “\<\<name\<\<endl;
}
int main()
{
Resume *r1 = new ResumeA(“A”);
Resume *r2 = new ResumeB(“B”);
Resume *r3 = r1->Clone();
Resume *r4 = r2->Clone();
r1->Show(); r2->Show();
//删除r1,r2
delete r1; delete r2;
r1 = r2 = NULL;
//深拷贝所以对r3,r4无影响
r3->Show(); r4->Show();
delete r3; delete r4;
r3 = r4 = NULL;
}
结构型模式
适配器模式(Adapter Pattern)
//兼容
//双端队列
class Deque
{
public:
void push_back(int x) { cout\<\<”Deque push_back”\<\<endl; }
void push_front(int x) { cout\<\<”Deque push_front”\<\<endl; }
void pop_back() { cout\<\<”Deque pop_back”\<\<endl; }
void pop_front() { cout\<\<”Deque pop_front”\<\<endl; }
};
//顺序容器
class Sequence
{
public:
virtual void push(int x) = 0;
virtual void pop() = 0;
};
//栈
class Stack: public Sequence
{
public:
void push(int x) { deque.push_back(x); }
void pop() { deque.pop_back(); }
private:
Deque deque; //双端队列
};
//队列
class Queue: public Sequence
{
public:
void push(int x) { deque.push_back(x); }
void pop() { deque.pop_front(); }
private:
Deque deque; //双端队列
};
int main()
{
Sequence *s1 = new Stack();
Sequence *s2 = new Queue();
s1->push(1); s1->pop();
s2->push(1); s2->pop();
delete s1; delete s2;
return 0;
}
桥接模式(Bridge Pattern)
//将抽象部分与它的实现部分分离,使它们都可以独立地变化。
//操作系统
class OS
{
public:
virtual void InstallOS_Imp() {}
};
class WindowOS: public OS
{
public:
void InstallOS_Imp() { cout\<\<”安装Window操作系统”\<\<endl; }
};
class LinuxOS: public OS
{
public:
void InstallOS_Imp() { cout\<\<”安装Linux操作系统”\<\<endl; }
};
class UnixOS: public OS
{
public:
void InstallOS_Imp() { cout\<\<”安装Unix操作系统”\<\<endl; }
};
//计算机
class Computer
{
public:
virtual void InstallOS(OS *os) {}
};
class DellComputer: public Computer
{
public:
void InstallOS(OS *os) { os->InstallOS_Imp(); }
};
class AppleComputer: public Computer
{
public:
void InstallOS(OS *os) { os->InstallOS_Imp(); }
};
class HPComputer: public Computer
{
public:
void InstallOS(OS *os) { os->InstallOS_Imp(); }
};
int main()
{
OS *os1 = new WindowOS();
OS *os2 = new LinuxOS();
Computer *computer1 = new AppleComputer();
computer1->InstallOS(os1);
computer1->InstallOS(os2);
}
过滤器模式(Filter、Criteria Pattern)
组合模式(Composite Pattern)
将对象组合成树形结构以表示“部分-整体”的层次结构。组合使得用户对单个对象和组合对象的使用具有一致性。注意两个字“树形”。这种树形结构在现实生活中随处可见,比如一个集团公司,它有一个母公司,下设很多家子公司。不管是母公司还是子公司,都有各自直属的财务部、人力资源部、销售部等。对于母公司来说,不论是子公司,还是直属的财务部、人力资源部,都是它的部门。整个公司的部门拓扑图就是一个树形结构。
装饰器模式(Decorator Pattern)
装饰模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征,相反,你可以定义一个简单的类,并且用装饰类给它逐渐地添加功能。可以从简单的部件组合出复杂的功能
外观模式(Facade Pattern)
class Scanner
{
public:
void Scan() { cout\<\<”词法分析”\<\<endl; }
};
class Parser
{
public:
void Parse() { cout\<\<”语法分析”\<\<endl; }
};
class GenMidCode
{
public:
void GenCode() { cout\<\<”产生中间代码”\<\<endl; }
};
class GenMachineCode
{
public:
void GenCode() { cout\<\<”产生机器码”\<\<endl;}
};
//高层接口
class Compiler
{
public:
void Run()
{
Scanner scanner;
Parser parser;
GenMidCode genMidCode;
GenMachineCode genMacCode;
scanner.Scan();
parser.Parse();
genMidCode.GenCode();
genMacCode.GenCode();
}
};
int main()
{
Compiler compiler;
compiler.Run();
return 0;
}
享元模式(Flyweight Pattern)
以围棋为例。棋盘中含两个共享的对象,黑棋子和白棋子,所有棋子的外在属性都存放在单独的容器中。
代理模式(Proxy Pattern)
为其他对象提供一种代理以控制对这个对象的访问。有四种常用的情况:(1)远程代理,(2)虚代理,(3)保护代理,(4)智能引用。
行为型模式
责任链模式(Chain of Responsibility Pattern)
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止,类中包含一个上级对象。
命令模式(Command Pattern)
解释器模式(Interpreter Pattern)
迭代器模式(Iterator Pattern)
中介者模式(Mediator Pattern)
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
备忘录模式(Memento Pattern)
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态
观察者模式(Observer Pattern)
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
状态模式(State Pattern)
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。它有两种使用情况:(1)一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。(2)一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。
空对象模式(Null Object Pattern)
策略模式(Strategy Pattern)
class A{
public:
virtual void print()=0;
}
class A1{
public:
void print(){cout>>“A1”;}
}
class A2{
public:
void print(){cout>>“A2”;}
}
class Cache{
private:
A *m_a;
public:
//方法一
Cache(A *a){m_a=a;}
//方法二
Cache(enum RA ra)
{
if(ra == LRU)
m_ra = new LRU_ReplaceAlgorithm();
else if(ra == FIFO)
m_ra = new FIFO_ReplaceAlgorithm();
else if(ra == RANDOM)
m_ra = new Random_ReplaceAlgorithm();
else
m_ra = NULL;
}
~Cache(){delete m_a;}
void print({m_a->print()})
}
int main()
{
Cache cache(new LRU_ReplaceAlgorithm()); //1.暴露了算法的定义
Cache cache(LRU); //2.指定标签即可
cache.print();
return 0;
}
模板模式(Template Pattern)
//模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
//简历
class Resume
{
protected: //保护成员
virtual void SetPersonalInfo() {}
virtual void SetEducation() {}
virtual void SetWorkExp() {}
public:
void FillResume()
{
SetPersonalInfo();
SetEducation();
SetWorkExp();
}
};
class ResumeA: public Resume
{
protected:
void SetPersonalInfo() { cout\<\<”A’s PersonalInfo”\<\<endl; }
void SetEducation() { cout\<\<”A’s Education”\<\<endl; }
void SetWorkExp() { cout\<\<”A’s Work Experience”\<\<endl; }
};
class ResumeB: public Resume
{
protected:
void SetPersonalInfo() { cout\<\<”B’s PersonalInfo”\<\<endl; }
void SetEducation() { cout\<\<”B’s Education”\<\<endl; }
void SetWorkExp() { cout\<\<”B’s Work Experience”\<\<endl; }
};
int main()
{
Resume *r1;
r1 = new ResumeA();
r1->FillResume();
delete r1;
r1 = new ResumeB();
r1->FillResume();
delete r1;
r1 = NULL;
return 0;
}