设计模式
1、简单工厂模式
- 工厂模式的概念是什么?
- 业务逻辑要与界面逻辑分开,让它们的耦合度降低。
- 紧耦合和松耦合
- 编程是一门技术,更是一门艺术,不能只满足于写完代码运行结果正确就完事了,时常考虑如何让代码更加简练,更加容易维护,容易扩展和复用,这样才能有所提高。
class OPeration{
private:
double number_A=0;
double number_B=0;
public:
virtual double GetResult(){
double res=0;
return res;
}
}
class OperationAdd:Operation{
double GetResult(){
return number_A+numner_B;
}
}
class OperationSub:Operation{
double GetResult(){
return number_A-number_B;
}
}
...
class OperationFactory{
public:
static Operation* createOperate(string operate){
Operation* oper=nullptr;
switch(operate){
case "+":
oper=new OperationAdd();
break;
case "-":
oper=new OperationSub();
break;
case "*":
oper=new OperationMul();
break;
case "/":
oper=new OperationDiv();
break;
}
return oper;
}
}
int main(){
Operation* oper=nullptr;
oper=OperationFactory::createOperate("+");
oper.Number_A=1;
oper.Number_B=2;
double res=oper.GetResult();
return 0;
}
2、策略模式(Strategy mode)
- 面相对象的编程,并不是类越多越好,类的划分是为了封装,但分类但基础是抽象,具有相同属性和功能的抽象集合才是类。例如打折,打一折和打九折只是形式的不同,抽象分析出来,所有的打折方法都是一样的,所以打折算法应该是一个类。
- 策略模式(Strategy):它定义类算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
3、单一职责模式
- 单一职责原则:就一个类而言,应该仅有一个引起它变化的原因[ASD]。
- 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏[ASD]。
4、开放—封闭模式
- 开放——封闭原则:软件实体(类、模块、函数等等)应该可以扩展,但是不可修改[ASD]。
- 这个原则其实有两个特征,一个是说“对于扩展是开放的(Open for extension)”,另一个是说“对于更改是封闭的(Closed for modification)”[ASD]。
- 在我们最初编写代码时,假设变化不会发生。当变化发生时,我们就创建抽象来隔离以后发生的同类变化[ASD]。
- 面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码[ASD]。
- 开放——封闭原则是面相对象设计的核心所在。遵循这个原则可以带来面相对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出频繁变化的那些部分作出抽象,然而,对于应用程序中的每个部分都进行抽象同样不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要[ASD]。
5、依赖倒转模式
- 高层模块和底层模块只依赖于接口或者抽象类
6、装饰模式
- 动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活
- 需要把所需的功能按正确的顺序串联起来进行控制
7、代理模式(proxy mode)
为其他对象提供一种代理以控制对这个对象的访问
8、工厂方法模式
定义一个接口,多个工厂实现这个接口
把简单工厂的switch取代,把调用和实现分开。没有违背开放—封闭原则。
class IFactory{
virtual Operation* CreateOperation();
}
class AddFactory{
public:
Operation* CreateOperation(){
return new OperationAdd();
}
}
class SubFactory{
public:
Operation* CreateOperation(){
return new OperationSub();
}
}
...
int main(){
IFactory operFactory=new AddFactory();
Operation oper=operFactory.CreateOperation();
oper.Number_A=1;
oper.Number_B=2;
double res=oper.GetResult();
return 0;
}
9、原型模式(prototype mode)
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
10、模板方法模式(template Method mode)
- 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
11、迪米特法则
最少知识原则
如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用
在类的结构设计上,每一个类都应当尽量降低成员的访问权限。即不需要让类知道的字段或行为就不要公开(private)
根本思想是 强调了类之间的松耦合
类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成设计
12、外观模式
- 为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
- 在设计初期阶段,应该有意识的将不同的两个层分离,层与层之间建立外观Facade.
其次在开发阶段,子系统因为不断的重构演化而变得越来越复杂,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖
在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,为新系统开发一个外观Facade类,来提供设计粗糙或高度复杂的遗留代码的比骄傲清晰简单的接口,让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作
13、建造者模式
- 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
- 又叫生成器模式。如果我们用了建造者模式,那么用户就只需指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需知道了
14、观察者模式
-
又叫发布-订阅模式
-
定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己
-
特点
-
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不变
-
当一个对象的改变需要同时改变其它对象,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式
一个抽象模型有两个方面,其中一个方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用 -
所做的工作其实就是在接触耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化
事件委托 -
委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其它任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的‘类’,委托的实例将代表一个具体的函数
一个委托可以搭载多个方法,所有方法被依次唤起。可以使得委托对象所搭载的方法并不需要属于同一个类
委托对象所搭载的所有方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值类型
#include <list> class ITeacherListenner { public: virtual void onTeacherComing(int value) = 0; }; //首先,先把通知者的行为抽象为一个接口:(subject) class INotifier { public: virtual void registerListenner(ITeacherListenner* l) = 0; virtual void removeListenner(ITeacherListenner* l) = 0; virtual void notify() = 0; }; //第二,然后班长作为一个具体的通知者:(ConcreteSubject) class MonitorNotifier : public INotifier{ public: void registerListenner(ITeacherListenner* l) { listenners.push_back(l); } void removeListenner(ITeacherListenner* l) { std::list<ITeacherListenner*>::iterator it; for (it = listenners.begin(); it != listenners.end(); ++it) { if (*it == l) { listenners.remove(l); break; } } } void notify() { std::list<ITeacherListenner*>::iterator it; for (it = listenners.begin(); it != listenners.end(); ++it) { (*it)->onTeacherComing(mValue); } } void setValue(int value) { mValue = value; notify(); } private: std::list<ITeacherListenner*> listenners; int mValue; }; //第三, 定义一个监听者的接口,想要监听老师来了这个消息的同学必须要实现这个接口: //这里先放到第一步之前了 //第四,ZhangSan 和 LiSi 监听了老师来了这个接口: class ZhangSan :public ITeacherListenner { public: void onTeacherComing(int value) { stopCopyWork(value); } void stopCopyWork(int value) { std::cout << "zhangsan stopCopyWork + " << value << std::endl; } }; class LiSi :public ITeacherListenner { public: void onTeacherComing(int value) { stopPlayGame(value); } void stopPlayGame(int value) { std::cout << "lisi stopPlayGame + " << value << std::endl; } }; int main() { MonitorNotifier monitor; ZhangSan zs; LiSi ls; monitor.registerListenner(&zs); monitor.registerListenner(&ls); monitor.setValue(1); return 0; }
15、抽象工厂模式
一个工厂生产多个实例,一个产品族
class IDepartment{
public:
virtual void Insert(Department department);
virtual Department GetDepartment(int id);
}
class SqlserverDepartment:IDepartment{
public:
void Insert(Department department){
std::cout<<"sql"<<std::endl;
}
Department GetDepartment(int id){
std::cout<<" cuvu"<<std::endl;
return null;
}
}
class AcessDepartment:IDepartment{
public:
void Insert(Department department){
std::cout<<"acc"<<std::endl;
}
Department GetDepartment(int id){
std::cout<<" "<<std::endl;
return null;
}
}
class IFactory{
virtual IUser* CreateUser();
//后增加的接口方法
virtual IDepartment* Createment();
}
class SqlServerFactory:IFactory{
public:
IUser* CreateUser(){
return new SqlseverUser();
}
IDepartment* CreateDepartment(){
return new SqlseverDepartment();
}
}
class AcessFactory:IFactory{
public:
IUser* CreateUser(){
return new AcessUser();
}
IDepartment* CreatDEpartment(){
return new AcessDepartment();
}
}
int main(){
User user=new User();
Department dept=new Department();
IFactory factory=new AcessFactory();
Iuser iu=factory.CreateUser();
iu.Insert(user);
iu.GetUser(1);
IDepartment id=factory.CreatDepartmentement();
id.Insert(dept);
id.GetDepartment(1);
return 0;
}
- 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
- 优缺点
- 好处便是易于交换产品系列,由于具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品
- 第二好处是让具体的创建实例过程与客户端分离,客户端通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码中
- 缺点是改动较大,可以用简单工厂来改进抽象工厂
17、适配器模式
- 将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
- 系统的数据和行为都正确,但接口不符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用与希望复用一些现存的类,但是接口又与复用环境要求不一致的情况
- 有两种类型:类适配器模式(用到多重继承)、对象适配模式
何时使用
- 使用一个已经存在的类,但如果它的接口,也就是它的方法和你要求不相同时,就应该考虑用适配器模式
- 两个类所做的事情相同或相似,但是具有不同的接口时要使用它
- 客户代码可以统一调用统一接口,可以更简单、更直接、更紧凑
- 在双方都不太容易修改的时候再使用适配器模式适配
class Target{
public:
virtual void request(){
std::cout<<"特殊请求"<<std::endl;
}
}
class Adaptee{
void specialRequest(){
std::cout<<"请求"<<std::endl;
}
}
class Adapter:public Target{
private:
Adaptee adaptee=new Adaptee();
public:
void request(){
adaptee.specialRequest();
}
}
//client
int main(){
Target target=new Target();
target.request();
return 0;
}
18、备忘录模式
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保持这个状态。这样以后就可将该对象恢复到原先保持的状态
20、迭代器模式
- 提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示
- 需要访问一个聚集对象,而且不管这些对象是什么都需要遍历的时候,你就应该考虑用迭代器模式
- 需要对聚集有多种方法遍历时,可以考虑用迭代器模式
- 为遍历不同的聚集结构提供如开始、下一个、是否结束、当前哪一项等统一的接口
- 分离了集合对象的遍历行为,抽象出一个迭代器来负责,这样可以做到不暴露集合的内部表示,又可以让外部代码透明地访问集合内部的数据
template<typename T>
class Iterator{
public:
virtual T First();
virtual T Next();
virtual bool IsDone();
virtual T CurretItem();
}
class Aggregate{
public:
virtual Iterator CreateAggregate();
}
template<typename T>
class ConcreteIterator:Iterator{
private:
ConcreteAggregate aggregate;
int current=0;
public:
ConcreteTterator(ConcreteAggregate aggregete){
this.aggregate=aggregate;
}
T First(){
return aggregate[0];
}
T Next(){
T ret=null;
++current;
if(current<aggregate.Count()){
ret=aggregate(current);
}
return ret;
}
bool IsDone(){
return current>=aggregate.Count;
}
T CurrentItem(){
return aggregate[current];
}
}
class ConcreteAggregate:Aggregate{
private:
list<T> items=new list<T>();
public:
Iterator CreateIterator(){
return new ConcreteIterator(this);
}
int Count(){
return items.size();
}
T operator[](int index){
return items[index];
}
}
int main(){
ConcreteAggregate a=new ConcreteAggregate();
a[0]="c";
..
a[5]="d";
Iterator i=new ConcreteIterator(a);
T item=i.First();
while(!i.isDone()){
std::cout<<i.CurrentItem()<<std::endl;
i.Next();
}
return 0;
}
21、单例模式
饥汉模式(静态初始化)
class SRIO{
private:
SRIO(){}
~SRIO(){}
SRIO& operator=(const SRIO&)=delete;
SRIO(SRIO&)=delete;
public:
static SRIO& getSRIO(){
static SRIO ret;
return ret;
}
}
懒汉模式(两次锁)
#include <memory>
#include <mutex>
class SRIO{
private:
SRIO(){}
~SRIO(){}
SRIO& operator=(const SRIO&)=delete;
SRIO(SRIO&)=delete;
public:
static std::shared_ptr<SRIO> getSRIO(){
if(m_SRIO==nullptr){
std::lock_guard<std::mutex> lc(m_mutex);
if(m_SRIO==nullptr){
m_SRIO=std::shared_ptr<SRIO>(new SRIO());
}
}
return m_SRIO;
}
private:
static std::shared_ptr<SRIO> m_SRIO=nullptr;
static std::mutex m_mutex;
}