设计模式的八个原则:
- 依赖倒置原则:高层次的代码(稳定)不应该依赖低层次的代码(变化)、抽象的代码不应该依赖具体的代码。
- 开放封闭原则:类模块应该开放扩展的,而其原先的代码尽量封闭不可改变。
- 单一职责原则:一个类应该仅有一个变化的原因,该变化隐含了它的职责,职责太多时会导致扩展时对代码东拉西扯,造成混乱。
- 替换原则:子类必须能够替换它的基类(IS-A),继承可以表达类型抽象。
- 接口隔离原则:接口应该小而完备,不该强迫用户使用多余的方法。
- 优先使用组合而不是继承:继承通常会让子类和父类的耦合度增加、组合的方式只要求组件具备良好定义的接口。
- 封装变化点:
- 针对接口编程,而不是针对实现编程。
重构关键技法
静态 动态
早绑定 晚绑定
继承 组合
编译时依赖 运行时依赖
紧耦合 松耦合
下面三个是组件协作类型的设计模式
框架和应用之间的关系
模板方法
类模式和对象方式:类强调继承,对象强调组合。
早绑定:晚写的代码调用早写的代码
晚绑定:早写的代码调用晚写的代码,延迟到子类,支持子类的变化。 稳定中有变化。
使用虚函数实现晚绑定,或者函数指针。
让库函数开发人员调用应用开发人员的代码。
有一个稳定的点,寻找出合适的隔离点。
红色是稳定的部分,蓝色是变化的部分。
策略模式
扩充的时候能够不修改源代码,创建新的类去计算,剩下的不变。比如税的计算方法,增加不同的国家对于会扩充税费的计算方法,但是只需要继承之前的策略实现新的策略就能够实现扩展。
枚举类型增加的时候需要修改代码
策略是可变的,但是基类的strategy和context是不变的,能够实现扩展且保持源代码稳定。
注意:如果有if-else
或者switch-case
的情况就很有可能使用策略模式。从使用角度将,一些不使用的判断就会耗费资源。占据缓存内存等,对性能问题有顺带的好处。
观察者模式
一对多的依赖关系,一个变化有多个更新。
addObserver(xxx)
随意的添加观察者的数量,目标发送通知时无需指定观察者,通过通知机制自动执行。
OnProgress()
就是通知,addObserver(xxx)
就是订阅,可以add
任意个观察者,目标无需考虑观察者,目标对象对此一无所知。
对象复用:享元模式FlyWeight
:对于大量存在的细粒度对象,会产生很大的内存消耗。维护一个对象池,当想要的对象在池中时,就不再创建,如果没有就新创建并加入,有点像线程池。
class FlyweightFactory
{
public:
~FlyweightFactory()
{
for ( auto it = flies.begin(); it != flies.end(); it++ )
{
delete it->second;
}
flies.clear();
}
Flyweight *getFlyweight( const int key )
{
if ( flies.find( key ) != flies.end() )
{
return flies[ key ];
}
Flyweight *fly = new ConcreteFlyweight( key );
flies.insert( std::pair<int, Flyweight *>( key, fly ) );
return fly;
}
// ...
private:
std::map<int, Flyweight*> flies;
// ...
};