目标:
整理设计模式知识,主要包含如下内容:
1、基础
2、单例模式
3、简单工厂
4、抽象工厂
5、策略模式
6、观察者模式
7、代理模式
第一部分 基础
1 面向对象的设计原则有哪些?
单一职责,开放封闭,依赖倒置,接口隔离,Liskov替换。
单一职责:一个类而言,仅有一个引起它变化的原因。判断如何分离类:多余一个动机改变一个类,这个类还需要分离
开放封闭原则:软件可以扩展,但不可以修改。扩展---开放,更改---封闭。适用:仅对程序中频繁变化的部分进行抽象
依赖倒转原则: 高层模块和底层模块都依赖抽象。
问题产生的原因:高层业务逻辑相同时,希望使用不同数据库,希望再利用高层模块,但高层模块与低层的访问数据库绑定在一起了。
本质:高层模块->接口/抽象类
|
低层模块
迪米特法则:最少知识原则。如果两个类不必直接通信,那么这两个类就不应当发生直接的相互作用。
如果其中一个类,需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
2 设计模式分类有哪些?
分为创建型模式,结构性模式,行为型模式
创建型模式: 用于处理对象创建,隐藏具体类的实例创建。主要有:单例,工厂,抽象工厂等
结构性模式: 装饰模式,代理模式等
行为型模式: 策略模式,观察者模式等
第二部分 单例模式
3 单例模式的作用?请编写一个。
1)保证一个类仅有一个实例,并提供全局访问点。
2)C++实现
#include<iostream>
#include<mutex>
#include<memory>
#include<string.h>
using namespace std;
template<typename T>
class Singleton{
private:
Singleton(){}
Singleton(const Singleton&){}
~Singleton(){}
Singleton& operator=(const Singleton&){}
public:
static T* instance()
{
if(0 == _instance.get())
{
std::unique_lock<std::mutex> uLock(_mutex);
if(0 == _instance.get())
{
std::shared_ptr<T> temp(new T);
_instance = temp;
}
}
return _instance.get();
}
private:
static std::shared_ptr<T> _instance;
static std::mutex _mutex;
};
template<typename T>
std::shared_ptr<T> Singleton<T>::_instance;
template<typename T>
mutex Singleton<T>::_mutex;
class Service
{
public:
void run()
{
cout<< "Service" << endl;
}
Service(){}
~Service(){}
};
typedef Singleton<Service> SService;
void process()
{
SService::instance()->run();
Service* p1 = SService::instance();
cout << p1 << endl;
Service* p2 = SService::instance();
cout << p2 << endl;
if(p1 == p2)
{
cout << "Singleton OK" << endl;
}else
{
cout << "Singleton Wrong" << endl;
}
}
int main(int argc, char* argv[])
{
process();
getchar();
return 0;
}
解释:
1 双重检查机制:
//先判断如果第一次创建,然后加锁,然后在判断是否为空,实例化;如果一进入就加锁,那么效率不好;
//如果判断完了再进入加锁,那么多个进程仍然会多次实例化,
if(0 == _instance.get())
{
//锁定互斥量,在构造时锁定互斥量,析构时自动解锁,保证互斥量的正确操作
std::unique_lock<std::mutex> uLock(_mutex);
if(0 == _instance.get())
2 //防止实例化失败,C++中对指针赋值操作并不能保证原子操作,如果有某个线程1执行到这里,
//赋值到一半,线程1挂起,线程2开始执行,这是_instance出于任何任何
std::shared_ptr<T> temp(new T);
_instance = temp;
第三部分 简单工厂
1 什么是简单工厂?请实现一个
1)在工厂类中做判断,从而创造相应的产品。增加新的产品时,就需要修改工厂类。
实例:一家生成处理器的厂家,一个工厂,能够产生两种型号的处理器核。客户需要什么样的处理器核,显示告诉生产工厂。
简单工厂缺点:增加新的产品类型,需要修改工厂类
2)大致代码如下
//简单工厂模式缺点:增加新类型需要修改工厂类
std::shared_ptr<SingleCore> Factory::instance(enum PRODUCT_TYPE type)
{
//工厂内部判断
if(type == COREA)
{
std::shared_ptr<SingleCore> ptrA(new SingleCoreA);
return ptrA;
}
else if(type == COREB)
{
std::shared_ptr<SingleCore> ptrB(new SingleCoreB);
return ptrB;
}
else
{
return NULL;
}
}
第四部分 抽象工厂
1 什么抽象工厂?请实现一个
1) 提供一个创建一系列相关或相互依赖对象的接口,
而无须指定他们具体的类。
简单工厂模式的最大优点:
工厂类中包含了必要的逻辑判断,根据客户端的选择实例化相关的类。对客户端来说,去除了具体产品的依赖。
缺点:增加功能,方法中需要对工厂类中增加条件判断,对扩展开放,对修改也开放。
抽象工厂缺点:如果要增加一个项目表,需要增加三个类,
IProject,SqlServerProject,AccessProject,
需要修改IFactory,SqlserverFactory,AccessFactory
抽象工厂实例:一个项目中使用多个数据库
2)
工厂类伪代码如下
//工厂A:专门用来生产A型号的处理器
shared_ptr<SingleCore> FactoryA::singleInstance()
{
shared_ptr<SingleCore> ptrA(new SingleCoreA);
return ptrA;
}
shared_ptr<MultiCore> FactoryA::multiInstance()
{
shared_ptr<MultiCore> ptrA(new MultiCoreA);
return ptrA;
}
//工厂B:专门用来生产B型号的处理器
shared_ptr<SingleCore> FactoryB::singleInstance()
{
shared_ptr<SingleCore> ptrA(new SingleCoreB);
return ptrA;
}
shared_ptr<MultiCore> FactoryB::multiInstance()
{
shared_ptr<MultiCore> ptrA(new MultiCoreB);
return ptrA;
}
调用类调用如下:
void process()
{
FactoryA factoryA;
shared_ptr<SingleCore> ptrSinA = factoryA.singleInstance();
if(ptrSinA)
{
ptrSinA->show();
}
shared_ptr<MultiCore> ptrMulA = factoryA.multiInstance();
if(ptrMulA)
{
ptrMulA->show();
}
FactoryB factoryB;
shared_ptr<SingleCore> ptrSinB = factoryB.singleInstance();
if(ptrSinB)
{
ptrSinB->show();
}
shared_ptr<MultiCore> ptrMulB = factoryB.multiInstance();
if(ptrMulB)
{
ptrMulB->show();
}
}
第五部分 策略模式
1 什么是策略模式?代码?
制定一系列的算法,然后封装起来,使他们可以相互替换。本模式使得算法
可以独立于使用它的客户而变化,算法完成的功能一样。只是各自实现存在差异。
实例:
Cache替换算法,有先进先出,LRU,随机
2
enum RA_TYPE{LRU , FIFO , RANDOM};//标签
template<class RA>
class Cache
{
public:
/*
Cache(void);
~Cache(void);
void replace();
*/
//传入标签,客户只需要知道算法的相应标签即可,不需要知道算法的具体定义。
Cache(enum RA_TYPE ra)
{
if(ra == LRU)
{
_ptrRA.reset(new LRU_ReplaceAlgorithm());
}
else if(ra == FIFO)
{
_ptrRA.reset(new FIFO_ReplaceAlgorithm());
}
else if(ra == RANDOM)
{
_ptrRA.reset(new Random_ReplaceAlgorithm());
}
else
{
_ptrRA = NULL;
}
}
Cache(void){}
~Cache(void){}
void replace(){_ra.replace();}
void replace2(){_ptrRA->replace();}
private:
RA _ra;
std::shared_ptr<ReplaceAlgorithm> _ptrRA;
};
第六部分 观察者模式
1 什么是观察者模式?具体组成是什么?代码
1)定义一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,
当这个主题对象状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
2)
Subject:通知者
Subject:它所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。
抽象主题提供接口,可以增加和删除观察者对象
Observer:抽象观察者,为所有的具体观察者定义一个接口。在得到主题的通知时更新自己。
ConcreteSubject:具体主题,将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知
ConcreteObserver:具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。
实际上就是双父类的风格,不要依赖具体,使得各自的变化不会影响另一边的变化。
3 伪代码如下:
主题:
class Boss :
public Subject
{
public:
Boss(void);
~Boss(void);
void attach(std::shared_ptr<Observer> ptrObserver);
void detach()
{
if(!_vecPtrObservers.empty())
{
}
}
void notify()
{
for(unsigned i = 0 ; i < _vecPtrObservers.size() ; i++)
{
_vecPtrObservers.at(i)->show();
}
}
private:
std::vector< std::shared_ptr<Observer> > _vecPtrObservers;
//可能这边强制转换为Observer导致多态失败,这里可能需要存放智能指针
std::string _sAction;
};
观察者:
//观察者被主题者通知
class Observer
{
public:
//Observer(const std::string& sName , Subject& subject);
Observer(const std::string& sName , std::shared_ptr<Subject> ptrSubject);
virtual ~Observer(void);
virtual void show();
protected:
std::string _sName;
std::shared_ptr<Subject> _ptrSubject;
};
调用者:
void process()
{
std::shared_ptr<Subject> mPtr(new Boss());
machaoPtr->_sStatus = "我归来";
std::shared_ptr<Observer> ptrStockObserver(new StockObserver("陈",mPtr));
std::shared_ptr<Observer> ptrNbaObserver(new NBAObserver("华",mPtr));
mPtr->attach(ptrStockObserver);
mPtr->attach(ptrNbaObserver);
mPtr->notify();
}
第七部分 代理模式
1 什么是代理模式?代码?
1)为其他对象提供一种代理以控制对这个对象的访问
Subject类:定义了RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方使用Proxy
例子:
安全代理:控制真是对象访问时的权限
关键:代理模式聚合了真正的主类去,在代理中的方法全部源自真正主类的方法
2
调用者:
void process()
{
SchoolGirl panyin("潘颖");
Proxy agent(panyin);
agent.giveChocolate();
agent.giveDolls();
agent.giveFlower();
}
class SchoolGirl
{
public:
SchoolGirl(const std::string& sName);
~SchoolGirl(void);
std::string getName();
public:
std::string _sName;
};
代理:
class Proxy :
public GiveGift
{
public:
Proxy(SchoolGirl& mm);
~Proxy(void);
void giveFlower();
void giveChocolate();
void giveDolls();
private:
std::shared_ptr<Pursuit> _ptrPursuit;//关键:代理模式聚合了真正的主类去,在代理中的方法全部源自真正主类的方法
};
参考:
王道程序员求职宝典
https://blog.csdn.net/qingyuanluofeng/article/details/39092085
https://blog.csdn.net/qingyuanluofeng/article/details/40567939
https://blog.csdn.net/qingyuanluofeng/article/details/47433729
https://blog.csdn.net/qingyuanluofeng/article/details/47433639
https://blog.csdn.net/qingyuanluofeng/article/details/47611433