下面是个人对部分模式设计的理解,权当做笔记了。
其实在了解模式设计之前,只知道实现,不知道思想,也没想过可扩展等功能,对于c++,也只是知道用它来实现面向过程,面向对象到底怎么样怎么用,全然无知,在此,谢谢带我进入模式设计的杨老师。
1.适配器模式
适配器模式将一个类的接口,转换成客户期望的另一个接口,适配器让原来接口不兼容的类可以合作无间。
客户使用适配器的过程:
1.客户通过目标接口调用适配器的方法对适配器发出请求
2.适配器使用被适配者接口把请求转换成被适配者的一个或多个调用接口
3.客户接收到调用的结果,并没有察觉到这一切是适配器在起转换作用
2.策略模式
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
3.代理模式
代理模式为另一个对象提供一个替身或占位符以控制这个对象的访问,被代理的对象可以有以下几种情况:
1.远程代理控制访问远程对象
2.虚拟代理控制访问创建开销大的资源
3.保护代理基于权限精致对资源的访问。
4.观察者模式
在对象间定义一对多的依赖,这样一来,当一个对象改变状态依赖它的对象都会收到通知,并自动更新。使用此模式,观察者获取数据可以自主去pull,也可以是被观察者push给观察者,当然push是更正确的,这也就应了好莱坞准,“你不要找我,我会打电话找你的”。
这里体现了松耦合的威力,即当两个对象之间松耦合,他们依旧可以交互,但是不太清楚彼此的细节,因此对象之间的相互依赖降到了最低。
1.在观察者模式的应用场景里变化的部分是
Subject
的状态和
Observer
的数量。使用
Observer
模式可以很好地将这两部分隔离开,我们可以任意改变
Observer
的数量而不需要去修改
Subject
,而
Subject
的状态也可以任意改变,同样不会对其
Observer
有任何影响。
2.Subject和Observer都使用接口来实现。Subject只需要跟踪那些实现了IObserver接口的对象,所以其只依赖于IObserver;而所有Observer都通过ISubject接口来注册、撤销、接收通知,所以它们也只依赖于 ISubject;所以这是面向接口编程的,这样的实现方式使得Subject和Observer之间完全没有任何耦合。
3.观察者模式使用对象组合将Subject和若干observer联系起来。它们之间的关系不是通过类的继承而是在运行时的动态组合。
5.装饰者
还没有完全的理解,暂且不写。
6.单件模式
应用于线程池,缓存,对话框处理,偏好设置,注册表等对象,这些对象只能有一个实例。
单件模式确保一个类只有一个实例,并且提供一个全局访问点。她有以下特点
1.单件模式确保程序中一个类最多只有一个实例
2.单件模式也提供访问这个实例的全局点
3.单件模式需要私有的构造函数,一个静态变量,一个静态方法。
4.在使用多线程时,一定要慎用单件模式。
代码示例:
#include <iostream>
using namespace std;
//单例类的C++实现
static int a=1;
class Singleton
{
private:
Singleton();//注意:构造方法私有
static Singleton* instance;//惟一实例
int var;//成员变量(用于测试)
public:
static Singleton* GetInstance();//工厂方法(用来获得实例)
static ClearInstance();
int getVar();//获得var的值
void setVar(int);//设置var的值
virtual ~Singleton();
};
//构造方法实现
Singleton::Singleton()
{
this->var = 20;
cout<<"Singleton Constructor"<<endl;
}
Singleton::~Singleton()
{
if(instance==NULL)
cout<<"Singleton Destructor"<<endl;
if(NULL!=instance)
{
cout<<"Singleton Destructor"<<endl;
//delete instance; 不注释掉会死循环的
instance=NULL;
a++;
}
}
//初始化静态成员
/*Singleton* Singleton::instance=NULL;
Singleton* Singleton::GetInstance()
{
if(NULL==instance)
instance=new Singleton();
return instance;
}*/
Singleton* Singleton::instance=new Singleton;
Singleton* Singleton::GetInstance()
{
return instance;
}
//seter && getter含数
int Singleton::getVar()
{
return this->var;
}
void Singleton::setVar(int var)
{
this->var = var;
}
Singleton::ClearInstance()
{
if(NULL != instance)
{
delete instance;
instance = NULL;
}
}
//main
void main()
{
Singleton *ton1 = Singleton::GetInstance();
Singleton *ton2 = Singleton::GetInstance();
if(ton1==ton2)
cout<<"ton1==ton2"<<endl;
cout<<"ton1 var = "<<ton1->getVar()<<endl;
cout<<"ton2 var = "<<ton2->getVar()<<endl;
ton1->setVar(150);
cout<<"ton1 var = "<<ton1->getVar()<<endl;
cout<<"ton2 var = "<<ton2->getVar()<<endl;
Singleton::ClearInstance();
delete Singleton::GetInstance();//必须显式地删除
cout<<a;
}
7.模板方法模式
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法可以使得子类可以在不改变算法的结构下,重新定义算法中的某些步骤。
1.模板方法为我们提供了方法复用的重要技巧
2.模板方法的抽象类可以定义具体方法,抽象方法和钩子
3.钩子是一种方法,它在抽象类中不做事,或者只做默认的事情,子类可以选择要不要去覆盖它
4.为了防止子类改变模板方法中的算法,可以将模板声明为const的
5.策略和模板都封装算法,但是一个是组合一个是继承
8.外观模式
外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
外观和适配器的一些要点:
1.当需要使用一个现有的类而其接口并不符合你的需要时,就是用适配器
2.当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观
3.适配器改变接口以符合客户的期望
4.外观将客户从一个复杂的子系统中解耦
5.实现一个适配器可能需要一番功夫,也可能不费功夫,视目标接口的大小与复杂度而定
6.实现一个外观,需要将子系统组合进外观中,然后将工作委托给子系统执行
7.适配器用两种,对象适配器和类适配器(需要用到多继承)。
8.适配器将一个对象包装起来以改变其接口,装饰者将一个对象包装起来以增加新的行为和责任,外观将一群对象包装起来简化接口
9.状态模式
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类
要点:
1.状态模式允许一个对象基于内部状态而拥有不同的行为
2.context会将行为委托给当前状态对象
3.通过将每个状态封装成类,我们以后需要做的任何改变局部化了
4.状态模式基于状态变化,策略模式基于算法改变
10.迭代器模式
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。