设计模式学习

前提:

  • 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。
  • 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

设计模式大体上分为3类

创建型设计模式:

五种:工厂方法模式抽象工厂模式单例模式、建造者模式、原型模式、

结构型设计模式:

七种:适配器模式装饰器模式代理模式、外观模式、桥接模式、组合模式、享元模式

行为型设计模式:

十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

下面主要详细展开抽象工厂模式,单例模式,适配器模式,装饰器模式,观察者模式

背景:小明家开了一个水果工厂,工厂主要卖苹果汁和橘子汁,现有有客户想下订单

下面主要出现三种苹果 (红富士,红星,红将军), 三种橘子 (沙糖桔,金橘,沃柑)

class fruit {
public:
    fruit() {}
    fruit(string name) : _name(name) {}
    virtual void show() = 0; // 纯虚函数声明
protected:
    string _name;
};

class apple :public fruit {
public:
    apple() {}
    apple(string name) :fruit(name) {}
    void show() {
        cout << "您下了苹果汁订单" << endl;
        if (_name.size() != 0) cout << ":" << _name << endl;
    }
};

class orange :public fruit {
public:
    orange() {}
    orange(string name) :fruit(name) {}
    void show() {
        cout << "您下了橘子汁订单" << endl;
        if (_name.size() != 0) cout << ":" << _name << endl;
    }
};

一 简单工厂模式

在刚开始的时候,小明家的水果工厂固定生产红富士大苹果和砂糖橘,每次下订单的时候,要先选择工厂(实例化工厂类simplefactory* factory = new simplefactory();),然后再从工厂里选择是苹果订单(fruit *p2=factory->createfruit(Apple);)。

enum cartype {
    Apple, Orange
};

class simplefactory {
public:
    fruit* createfruit(cartype ct) {
        switch (ct) {
        case Apple:
            return new apple("红富士");
            break;
        case Orange:
            return new orange("沙糖桔");
            break;
        default:
            cout << "没有这个水果" << endl;
            break;
        }
    }
};

int main() {

    simplefactory* factory = new simplefactory();
    fruit *p2=factory->createfruit(Apple);
    p2->show();
    delete p2;
    delete factory;
    return 0;
}

二  工厂方法

  • 定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

小明家的工厂做大做强,除了红富士大苹果和沙糖桔,还有红星苹果和金橘

如果使用简单工厂方法的话,就得扩充上面的switch语句,更加细分苹果的种类和橘子的种类

有点像是把水果分成了四种:红富士大苹果,红星苹果,沙糖桔,金桔

这个时候可以使用工厂方法,细分苹果生产橘子生产

  • 先将将水果工厂分为苹果工厂和橘子工厂,让用户先选择水果种类,
  • 再选择水果种类名称。
class factory {
public:
    virtual fruit* createfruit(string name) = 0;
};

class applefactory:public factory {
public:
    fruit* createfruit(string name) {
        return new apple(name);
    }
};

class orangefactory:public factory {
public:
    fruit* createfruit(string name) {
        return new orange(name);
    }
};

int main() {
    factory* p1 = new applefactory();
    fruit* orange1=p1->createfruit("红富士");
    factory* p2 = new orangefactory();
    fruit* apple1=p1->createfruit("洛川");
    apple1->show();
    orange1->show();
    return 0;
}

三 抽象工厂

  • 抽象工厂模式是围绕一个超级工厂创建其他工厂

已经知道上面小明家的工厂可以生产不同种类的苹果汁和橘子汁,现在小明家开拓业务,想要生产橘子罐头和苹果罐头,首先添加罐头class tin,以及派生类class appletin:public tin和派生类 class orangetin:public tin类 

class tin{
public:
    virtual void show()=0;
};
class appletin:public tin{
public:
    void show(){
        cout<<"下单了苹果罐头"<<endl;
    }
};
class orangetin:public tin{
public:
    void show(){
        cout<<"下单了橘子罐头"<<endl;
    }
};

如果按照二 中的工厂方法的模式,现在要再新创class appletin:public factory和class orangetin:public factory

但是苹果汁和苹果罐头都是由苹果制成的,应该都归类为苹果工厂;橘子汁和橘子罐头都是由橘子制成的,应该都归类为橘子工厂,所以使用抽象工厂。

class abstractfactory {
public:
    virtual tin* createtin() = 0;
    virtual fruit* createfruit(string name) = 0;
};

class applefactory :public abstractfactory {
    tin* createtin() {
        return new appletin();
    }
    fruit* createfruit(string name) {
        return new apple(name);
    }
};
class orangefactory :public abstractfactory {
    tin* createtin() {
        return new orangetin();
    }
    fruit* createfruit(string name) {
        return new orange(name);
    }
};

int main() {
    abstractfactory* p1 = new applefactory();
    tin* p2 = p1->createtin();
    fruit* p3 = p1->createfruit("红富士");
    p2->show();
    p3->show();
    delete p3;
    delete p2;
    delete p1;
	return 0;
}

这样的话,有关联的苹果汁和苹果罐头都放在了一起,有关联的橘子汁和橘子罐头都放在一起,橘子产线和苹果产线分开

四 单例模式

  • 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

背景:现在有厂商准备下一批订单,想要下小明家工厂的苹果汁,后来觉得好喝,准备下单橘子汁。(厂商每次下订单,就是实例化一下小明家工厂,但是每次生成的工厂对象都是一个从零开始的工厂对象,怎么样才能让实例化的对象永远是同一家呢,保持之前的状态呢)

4.1 饿汉单例模式: 对象在类创建时就已经构建

在这个类的实现中,通过使用静态成员变量和静态成员函数,可以实现对单例对象的访问和订单次数的统计,同时通过私有化构造函数、删除拷贝构造函数和赋值构造函数,确保了该类只能有一个实例对象,并且无法被复制或赋值

//饿汉式单例模式
class xiaomingfactory {
public:
    static xiaomingfactory* getinstance() {
        return &instance;
    }
    static void show() {
        p++;
        cout << "第" << p << "次在小明家下单。" << endl;
    }
private:
    static int p;
    static xiaomingfactory instance;
    xiaomingfactory() {
        
    }//构造函数
    xiaomingfactory(const xiaomingfactory&) = delete; //不能进行拷贝构造函数
        xiaomingfactory& operator=(const xiaomingfactory&) = delete; //不能进行赋值构造函数
};

int xiaomingfactory::p=0;
xiaomingfactory xiaomingfactory::instance;
int main() {
    xiaomingfactory* p1 = xiaomingfactory::getinstance();
    p1->show();
    xiaomingfactory* p2 = xiaomingfactory::getinstance();
    p2->show();
    xiaomingfactory* p3 = xiaomingfactory::getinstance();
    p3->show();
    return 0;
}

4.2 懒汉单例模式:对象在调用时构建

//懒汉式单例模式

class xiaomingfactory {
public:
    static xiaomingfactory* getinstance() {
        static xiaomingfactory instance;
        static int p;
        p++;
        cout << "第" << p << "次下单小明家商品" << endl;
        return &instance;
    }
private:
    xiaomingfactory() {}
    xiaomingfactory(const xiaomingfactory&) = delete;
    xiaomingfactory& operator=(const xiaomingfactory&) = delete;
};

int main() {
    xiaomingfactory* p1 = xiaomingfactory::getinstance();
    xiaomingfactory* p2 = xiaomingfactory::getinstance();
    xiaomingfactory* p3 = xiaomingfactory::getinstance();
    return 0;

}

五 适配器模式

  • 适配器模式是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
  • 这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。

背景:上面说到小明家的工厂有刚开始有果汁产业,后来引入罐头产业,那么生产果汁的流水线能不能给生产罐头用呢,小明家准备将之前的流水线改造一下,加一个适配器,让生产果汁的流水线也能部分来生产罐头。

 有点像加了一个判断,流水线前面都需要对水果进行处理,在中途,有两个选择,如果接收到时果汁的信号,流水线下面进程不变,如果时罐头信号,流水线开关打向做罐头的

class fruit {public: virtual void use()= 0; };
class apple :public fruit {public: void use() { cout << "设备用来生产苹果汁" << endl; } };
class tin {public: virtual void use()= 0; };
class appletin :public tin { public: void use() { cout << "设备用来生产苹果罐头" << endl; } };
class liushuixian {
public:
    void show(fruit* p1) {
        p1->use();
    }
};

class liushuixianadapter :public fruit, public tin {
public:
    liushuixianadapter(tin* p) :p1(p) {}
    void use() { p1->use(); }
private:
    tin* p1;
};

int main() {
    liushuixian* p1 = new liushuixian();
    p1->show(new liushuixianadapter(new appletin()));
    liushuixian* p2 = new liushuixian();
    p2->show(new apple());
    return 0;
}

六 装饰者模式

  • 装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
  • 装饰器模式通过将对象包装在装饰器类中,以便动态地修改其行为。
  • 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

背景:还是小明家的工厂,现在客服想要用小明家的水果罐头来联名西游记,联名任务有孙悟空,猪八戒,沙僧,几种任务罐头都有,而且还有隐藏罐头,3个人全有的罐头

 如果在罐头实例中修改,太过麻烦,代码不整洁,是否可以有一种选择,在类外实现,并且联名结束后,直接删除外面的代码。这样简洁且不容易出错。

class decorator :public tin {
public:
    decorator(tin* p) :p1(p) {}
    virtual void show() = 0;
protected:
    tin* p1;
};

class swkdecorator :public decorator {
public:
    swkdecorator(tin* p) :decorator(p) {}
    void show() {
        p1->show();
        cout << "包括孙悟空联名" << endl;
    }
};

class zbjdecorator :public decorator {
public:
    zbjdecorator(tin* p) :decorator(p) {}
    void show() {
        p1->show();
        cout << "包括猪八戒联名" << endl;
    }
};

class szdecorator :public decorator {
public:
    szdecorator(tin* p) :decorator(p) {}
    void show() {
        p1->show();
        cout << "包括沙僧联名" << endl;
    }
};

int main() {
    tin* p1 = new swkdecorator(new appletin());
    p1->show();
    tin* p2 = new szdecorator(new orangetin());
    p2 = new zbjdecorator(p2);
    p2->show();
    return 0;
}

七 代理者模式

  • 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

背景:现在有很多客户想要下单小明家的水果罐头,小明家给这些客服分为了普通客户和vip客户(普通用户可以购买普通商品,不可以购买折扣商品;vip用户可以购买普通商品也可以购买折扣商品)。客户下单时,需要拨打电话给秘书(代理),秘书确认客户的等级身份。

#include<iostream>
#include<string>
using namespace std;

class abstraclevel {//抽象类
public:
    virtual void freelevel() = 0;
    virtual void viplevel() = 0;
};

class level : public abstraclevel {//委托类
public:
    virtual void freelevel() {
        cout << "您可以购买普通商品" << endl;
    }
    virtual void viplevel() {
        cout << "您可以购买折扣商品" << endl;
    }
};

class freeclientlevel :public abstraclevel {//代理类
public:
    freeclientlevel() { p1 = new level(); }
    ~freeclientlevel() { delete p1; }
    virtual void freelevel() {
        p1->freelevel();
    }
    virtual void viplevel() {
        cout << "您目前是普通用户,需要升级成vip用户,才能购买折扣商品" << endl;
    }
private:
    abstraclevel* p1;
};

class vipclientlevel : public abstraclevel {//代理类
public:
    vipclientlevel() { p1 = new level(); }
    ~vipclientlevel() { delete p1; }
    virtual void freelevel() {
        p1->freelevel();
    }
    virtual void viplevel() {
        p1->viplevel();
    }
private:
    abstraclevel* p1;
};


int main() {
    abstraclevel* p1 = new freeclientlevel();
    p1->freelevel();
    p1->viplevel();
    abstraclevel * p2 = new vipclientlevel();
    p2->freelevel();
    p2->viplevel();
    return 0;
}

八 观察者模式

  • 观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。
  • 当对象间存在一对多关系时,则使用观察者模式。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。

背景:现在有张总,李总,王总是小明家的客户,张总关注苹果和橘子汁的价格变化,李总关注苹果汁的价格变化,王总关注橘子汁的价格变化。现在假设苹果汁价格发生变化用标号1代替,橘子汁发生变化,用标号2代替。

小明家工厂中的苹果和橘子汁价格发生变化时,会通知对应的老总。

所以创建一个观察者抽象类 class observer和三个用户实例 class userzhang,class userli,class userwang.

小明家有一个subject管理器,负责用来登记用户,以及用户对应关注的信息。以及当自家水果价格发生变化后,发送给对应的客户水果价格信息。

#include<iostream>
#include<unordered_map>
using namespace std;
class observer {
public:
	virtual void handler(int num) = 0;
	int num;
};
class userzhang:public observer {
public:
	void handler(int num) {
		switch (num) {
		case 1:
			cout << "张总收到苹果汁价格变化的通知" << endl;
			break;
		case 2:
			cout << "张总收到橘子汁价格变化的通知" << endl;
			break;
		default:
			cout << "通知发错了" << endl;
		}
	}
};

class userli :public observer {
public:
	void handler(int num) {
		switch (num) {
		case 1:
			cout << "李总收到苹果汁价格变化的通知" << endl;
			break;
		default:
			cout << "通知发错了" << endl;
		}
	}
};

class userwang :public observer {
public:
	void handler(int num) {
		switch (num) {
		case 2:
			cout << "王总收到橘子汁价格变化的通知" << endl;
			break;
		default:
			cout << "通知发错了" << endl;
		}
	}
};

class subject {
public:
	void adduser(observer * p,int num) {
		userregister[num].push_back(p);//加入用户
	}
	void receive(int num) {
		auto f=userregister.find(num);
		if (f != userregister.end()) {
			for (observer* p : f->second) {
				p->handler(num);
			}
		}

	}
private:
	unordered_map<int, list<observer*>> userregister;
};
int main() {
	subject subj;
	observer* p1 = new userzhang();
	observer* p2 = new userli();
	observer* p3 = new userwang();
	subj.adduser(p1,2);
	subj.adduser(p1,1);
	subj.adduser(p2,1);
	subj.adduser(p3,2);
	subj.receive(2);
	subj.receive(1);

	return 0;
}

参考:

23 种设计模式详解(全23种) - 知乎 (zhihu.com)

软件设计模式_百度百科 (baidu.com)

菜鸟教程 - 学的不仅是技术,更是梦想! (runoob.com)

  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值