李建忠老师讲的,以前B站有,后来被删了,只能上youtube看了添加链接描述
以前听过几堂课,代码写的少并没有真正的理解,自己网站前一阵子更新了一波代码突然发现代码之间组合竟然设计的紊乱,所以重新认真的学习一下。
重要的原则
记住依赖倒置原则、针对接口编程而不是实现编程,依赖抽象而不是具体实现的细节,比如有一个类需要调用跑车,我们不要真的调用跑车这个类,而是要让代码调用汽车这个类,跑车这个类继承汽车类。这样的好处就是如果添加SUV这个类不需要在重新一遍相似的代码,这样提高复用性。
封闭开放原则也是,划分成稳定和变化的因素
好好利用晚绑定,利用虚函数和多态。模板方法、策略模式、观察者模式还是利用抽象来拆解具体实现的细节的模式。
理解且记住这些原则背后的思想比记住模式的架构有用100倍
装饰模式
他和桥接模式都是发现子类代码重复高,没有好的复用的时候来进行改造的
using byte = char;
//业务操作
class Stream
{
public:
virtual char Read(int number) = 0;
virtual void Seek(int position) = 0;
virtual void Write(char data) = 0;
virtual ~Stream() {}
};
//主体类
class FileStream : public Stream
{
public:
virtual char Read(int number)
{
//读文件流
}
virtual void Seek(int position)
{
//定位文件流
}
virtual void Write(char data)
{
//写文件流
}
};
class NetworkStream : public Stream
{
public:
virtual char Read(int number)
{
//读网络流
}
virtual void Seek(int position)
{
//定位网络流
}
virtual void Write(char data)
{
//写网络流
}
};
class MemoryStream : public Stream
{
public:
virtual char Read(int number)
{
//读内存流
}
virtual void Seek(int position)
{
//定位内存流
}
virtual void Write(char data)
{
//写内存流
}
};
class decorate : public Stream {
protected:
Stream* stream_;
decorate(Stream* stm):stream_(stm){}
};
//扩展操作
class CryptoStream : public decorate
{
public:
CryptoStream(Stream* stm):decorate(stm){}
virtual char Read(int number)
{
//额外的加密操作...
stream_->Read(number); //读文件流
}
virtual void Seek(int position)
{
//额外的加密操作...
stream_->Seek(position); //定位文件流
//额外的加密操作...
}
virtual void Write(byte data)
{
//额外的加密操作...
stream_->Write(data); //写文件流
//额外的加密操作...
}
};
class BufferedStream : public decorate
{
public:
BufferedStream(Stream* stm):decorate(stm){}
virtual char Read(int number)
{
//额外的加密操作...
//额外的缓冲操作...
stream_->Read(number); //读文件流
}
virtual void Seek(int position)
{
// 应该再加一个模板方式的,启动这个seek
//额外的加密操作...1
//额外的缓冲操作...2
stream_->Seek(position); //定位文件流3
//额外的加密操作...4
//额外的缓冲操作...5
}
virtual void Write(byte data)
{
//额外的加密操作...
//额外的缓冲操作...
stream_->Write(data); //写文件流
//额外的加密操作...
//额外的缓冲操作...
}
};
void Process()
{
//编译时装配
FileStream* s1 = new FileStream();
CryptoStream* s2 = new CryptoStream(s1);
BufferedStream* s3 = new BufferedStream(s1);
BufferedStream* s4 = new BufferedStream(s2);
s4->Write('1');
}
decorate 这个类为什么要继承Stream呢?因为他下面的功能如果混合使用的话,构造参数就需要传参数s2(Process里的),如果不继承Stream,s2的参数类型就转换成Stream
工厂模式
/*
* 为什么需要工厂类?
* 像下面这个例子,其实我认为是完全不需要工厂类的,MainForm的
* factory类型换成ISplitter是完全可代替的。
* 但工厂模式秒处在哪里呢?这是一个产品,但如果我需要两个产品
* 比如键盘和鼠标,鼠标和键盘都是抽象基类,没有共同祖先,这时候MainForm
* 一个变量就不够了,但如果是Factory类型,就说明还是他一个就行,工厂这个
* 抽象基类相当于万物的鼻祖了。
*/
//抽象类
class ISplitter
{
public:
virtual void split() = 0;
virtual ~ISplitter() {}
};
//工厂基类
class SplitterFactory
{
public:
virtual ISplitter* CreateSplitter() = 0;
virtual ~SplitterFactory() {}
};
//具体类
class BinarySplitter : public ISplitter
{
public:
void split() {
}
};
class TxtSplitter : public ISplitter
{
};
class PictureSplitter : public ISplitter
{
};
class VideoSplitter : public ISplitter
{
};
//具体工厂
class BinarySplitterFactory : public SplitterFactory
{
public:
virtual ISplitter* CreateSplitter()
{
return new BinarySplitter();
}
};
class TxtSplitterFactory : public SplitterFactory
{
public:
virtual ISplitter* CreateSplitter()
{
return new TxtSplitter();
}
};
class PictureSplitterFactory : public SplitterFactory
{
public:
virtual ISplitter* CreateSplitter()
{
return new PictureSplitter();
}
};
class VideoSplitterFactory : public SplitterFactory
{
public:
virtual ISplitter* CreateSplitter()
{
return new VideoSplitter();
}
};
class MainForm : public Form
{
SplitterFactory* factory; //工厂
public:
MainForm(SplitterFactory* factory)
{
this->factory = factory;
}
void Button1_Click()
{
ISplitter* splitter = factory->CreateSplitter(); //多态new
splitter->split();
}
};
抽象工厂
就是多个工厂,每个工厂可能会有依赖,但是呢如果传错一个值就不能用了,整了一个超级工厂作为这些工厂的鼻祖来避免传错值。
原型模式
就是把工厂和那个类合并,然后传一个深拷贝的值,主要就是为了返回这个对象
构建器模式
把初始的代码单独拎出来,因为在基类构造函数不能调用虚函数
享元模式
对象池的思想,这个对象如果创建过就直接返回,否则创建一个新对象,对象是共享的,和线程池一样的
门面模式
相当于加了一个间接层,变化和稳定分隔开
代理模式
当因为多进程或者分布式我们拿不到类对象的时候,使用的模式,这样使用代理模式来进行连接
适配器模式
出现新的接口,为了兼容老接口,适配器继承了新接口然后组合老接口,实现新老接口兼容。继承新接口,组合老接口对象
中介者模式
什么时候使用?多个对象互相关联的情况时候使用。
状态模式
就是把枚举类型变成具体类,他们都继承一个抽象类,这样用稳定来替换未来可能发生变换的地方。
备忘录模式
不破坏封装,捕获对象内部状态,序列化反序列化已经可以代替了
组合模式
例子很像muduo库添加事件发生的时候的,遍历事件利用多态来实现不同的功能
迭代器模式
可以用模板来实现。不关心内部的表示
职责链模式
还是利用多态虚函数实现代码复用,解决的问题:当前对象处理不了业务顺延到下一个对象去处理,直到有一个对象可以处理这个业务。用的也很少。感觉和if-else没啥区别,也是判断这个对象能不能处理不能就一个对象
命令模式
在C++中可以利用函数对象(就是重载())+模板来实现来实现这个模式
访问器模式
新增需求避免修改源代码,新增访问器类,新增需求新增一个类从而避免修改源代码,也没有破坏开闭原则。这是个好东西啊
demo
最后做一个小玩具出来玩玩,一个比较小的日志系统,github链接