每天一个设计模式——装饰模式(C++实现)

设计模式的代码十分难写的,要充分的体现可复用性,网上有着大量关于设计模式的代码,其中很多的代码违背了很多设计原则,比如依赖倒置原则、开放封闭原则,需要我们明辨是非。

设计模式的原则大于使用哪个设计模式,类的组合关系也大于类的继承,通过不断的写代码加上多思考多总结才能真正的领悟大师们的思想。

我看的是李健忠老师的设计模式
课程链接
课程配套的源码


以下源代码第一份和第二份是我摘录课程的源码,第三份是经过我自己的想法与总结写的,我也建议大家学习一个模式,先动手把最初的代码改一改,这样能增加对这个模式的理解,而不是老师讲了什么才知道什么。

第一份代码

先让我们看看第一份代码,FileStream、 NetworkStream、MemoryStream要重写Read等一系列虚函数,这个是没问题的。可以当他们要实现一个功能的时候(加密呀等等功能,实现的功能不需要重写),而如果继续采用继承的话,功能分别继承FileStream、 NetworkStream、MemoryStream这些类,多一个功能,就要改变N个类,这样的维护性大大的减少了。这也违反了依赖倒置原则,高层模块不应该依赖低层模块,**应该都依赖抽象(基类)**我们进行改正一下,往下翻看第二份代码

//第一版代码
//业务操作
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 CryptoFileStream :public FileStream{
public:
    virtual char Read(int number){
       
        //额外的加密操作...
        FileStream::Read(number);//读文件流
        
    }
    virtual void Seek(int position){
        //额外的加密操作...
        FileStream::Seek(position);//定位文件流
        //额外的加密操作...
    }
    virtual void Write(byte data){
        //额外的加密操作...
        FileStream::Write(data);//写文件流
        //额外的加密操作...
    }
};

class CryptoNetworkStream : public NetworkStream{
public:
    virtual char Read(int number){
        
        //额外的加密操作...
        NetworkStream::Read(number);//读网络流
    }
    virtual void Seek(int position){
        //额外的加密操作...
        NetworkStream::Seek(position);//定位网络流
        //额外的加密操作...
    }
    virtual void Write(byte data){
        //额外的加密操作...
        NetworkStream::Write(data);//写网络流
        //额外的加密操作...
    }
};

class CryptoMemoryStream : public MemoryStream{
public:
    virtual char Read(int number){
        
        //额外的加密操作...
        MemoryStream::Read(number);//读内存流
    }
    virtual void Seek(int position){
        //额外的加密操作...
        MemoryStream::Seek(position);//定位内存流
        //额外的加密操作...
    }
    virtual void Write(byte data){
        //额外的加密操作...
        MemoryStream::Write(data);//写内存流
        //额外的加密操作...
    }
};

class BufferedFileStream : public FileStream{
    //...
};

class BufferedNetworkStream : public NetworkStream{
    //...
};

class BufferedMemoryStream : public MemoryStream{
    //...
};




class CryptoBufferedFileStream :public FileStream{
public:
    virtual char Read(int number){
        
        //额外的加密操作...
        //额外的缓冲操作...
        FileStream::Read(number);//读文件流
    }
    virtual void Seek(int position){
        //额外的加密操作...
        //额外的缓冲操作...
        FileStream::Seek(position);//定位文件流
        //额外的加密操作...
        //额外的缓冲操作...
    }
    virtual void Write(byte data){
        //额外的加密操作...
        //额外的缓冲操作...
        FileStream::Write(data);//写文件流
        //额外的加密操作...
        //额外的缓冲操作...
    }
};



void Process(){

        //编译时装配
    CryptoFileStream *fs1 = new CryptoFileStream();

    BufferedFileStream *fs2 = new BufferedFileStream();

    CryptoBufferedFileStream *fs3 =new CryptoBufferedFileStream();

}

第二份代码

对额外的功能新增一个基类,在使用组合的方式替代继承,提高代码复用性,在实际的工程已经可以了。对象Stream* stream并没有得到复用,在细致的话就要引出装饰模式,往下翻看第三份代码

//业务操作
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 CryptoStream: public Stream {
    
    Stream* stream;//...

public:
    CryptoStream(Stream* stm):stream(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 Stream{
    
    Stream* stream;//...
    
public:
    BufferedStream(Stream* stm):stream(stm){
        
    }
    //...
};





void Process(){

    //运行时装配
    FileStream* s1=new FileStream();
    CryptoStream* s2=new CryptoStream(s1);
    
    BufferedStream* s3=new BufferedStream(s1);
    
    BufferedStream* s4=new BufferedStream(s2);
    
    

}

第三份代码

给所有的功能在套上一个基类(Decorate类),Stream的对象也能得到了复用

//业务操作
class Stream {
public:
    virtual char Read(int number) = 0;
    virtual void Seek(int position) = 0;
    virtual void Write(int data) = 0;

    virtual ~Stream() {}
};

//主体类
class FileStream : public Stream {
public:
    virtual char Read(int number) {
        //读文件流
    }
    virtual void Seek(int position) {
        //定位文件流
    }
    virtual void Write(int data) {
        //写文件流
    }

};

class NetworkStream :public Stream {
public:
    virtual char Read(int number) {
        //读网络流
    }
    virtual void Seek(int position) {
        //定位网络流
    }
    virtual void Write(int data) {
        //写网络流
    }

};

class MemoryStream :public Stream {
public:
    virtual char Read(int number) {
        //读内存流
    }
    virtual void Seek(int position) {
        //定位内存流
    }
    virtual void Write(int data) {
        //写内存流
    }

};
class Decorator :public Stream {
    //继承了这个类并且声明这个类的对象99%的可能性就是装饰模式了
public:
    //为什么需要Decorator?
    //因为这个Steam对象也是共用的,并且会有多个扩展操作,
    //这样也使用了依赖倒置原则,具体的类(File、Network...)与
    //可扩展的类(具体操作)通过Decorator这个抽象实现的通信
    //Decorator通过他的上层Stream来进一步通信
    Stream* stm; // new Stream();
    Decorator(Stream* stm) :stm(stm) {

    }
};

//扩展操作
//增加新的共用的功能,通过组合的形式,而不是每个类通过继承上一个类解决问题
class CryptoStream :public Decorator {//这样三种文件都可以通过这样的一个类
public: 
    CryptoStream(Stream* stm) : Decorator(stm) {}
    virtual char Read(int number) {

        //额外的加密操作...
        stm->Read(number);//读文件流

    }
    virtual void Seek(int position) {
        //额外的加密操作...
        stm->Seek(position);//定位文件流
        //额外的加密操作...
    }
    virtual void Write(int data) {
        //额外的加密操作...
        stm->Write(data);//写文件流
        //额外的加密操作...
    }
};


class BufferedStream : public Decorator {
    //...
};



class CryptoBufferedStream :public Decorator {
public:
    virtual char Read(int number) {

        //额外的加密操作...
        //额外的缓冲操作...
        stm->Read(number);//读文件流
    }
    virtual void Seek(int position) {
        //额外的加密操作...
        //额外的缓冲操作...
        stm->Seek(position);//定位文件流
        //额外的加密操作...
        //额外的缓冲操作...
    }
    virtual void Write(int data) {
        //额外的加密操作...
        //额外的缓冲操作...
        stm->Write(data);//写文件流
        //额外的加密操作...
        //额外的缓冲操作...
    }
};



void Process() {


    //运行时装配
    Stream* f = new FileStream();
    Decorator* fs1 = new CryptoStream(f);
    Stream* f2 = new CryptoStream(f);
    //BufferedFileStream* fs2 = new BufferedFileStream();

  //  CryptoBufferedFileStream* fs3 = new CryptoBufferedFileStream();

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值