Design Pattern - popular patterns learning<Learning Note>设计思维常用模式学习<学习笔记>

本文详细介绍了单例模式、工厂模式、观察者模式、策略模式、模板方法模式和代理模式的特点、应用场景及优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Preface:This article is written for a nifty girl who I cherish.

在这里插入图片描述

单例模式,工厂模式,观察者模式,策略模式,模板方法模式,代理模式

(0)Singleton Pattern(单例模式)

Features: 一个类只有一个对象的实例
Example: 日志管理、打印机、数据库连接池、应用配置
Merit: 节省公共资源;方便控制,同一时间只有一个人占用
Design Method: 保证一个类不能多次被实例化,那么我肯定要阻止对象被new 出来,所以需要把类的所有构造方法私有化

  • 饿汉模式:
class Singleton
{
private:
	static Singleton instance;
private:
	Singleton();
	~Singleton();
	Singleton(const Singleton&);
	Singleton& operator=(const Singleton&);
public:
	static Singleton& getInstance() {
		return instance;
	}
}
// initialize defaultly
Singleton Singleton::instance;

对象已经创建好,等待被调用(但容易资源浪费)

  • 懒汉模式:
// version 1.2
class Singleton
{
private:
	Singleton() { };
	~Singleton() { };
	Singleton(const Singleton&);
	Singleton& operator=(const Singleton&);
public:
	static Singleton& getInstance() 
        {
		static Singleton instance;
		return instance;
	}
};
Singleton& s=Singleton::getInstance();

不创建类的对象实例,需要用到的时候再创建,需要加上锁,对象只能被实例化一次(加锁会影响程序运行效率,解决方法:双重检查锁DCL,只有当对象未创建的时候才对请求加锁,对象创建以后都不会上锁)
C++11规定了local static在多线程条件下的初始化行为,要求编译器保证了内部静态变量的线程安全性

Merits:

  • 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)
  • 避免对资源的多重占用(比如写文件操作)

Demerit: 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化

(1)Factory Pattern(工厂模式)

Features: 建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象,主要解决接口选择的问题,复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式
Example:
工厂类负责创建的对象比较少;
客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心;
由于简单工厂很容易违反高内聚责任分配原则,因此一般只在很简单的情况下应用。
Design Methods:

  • 简单工厂模式
//product class
class Product{
public:
	virtual int operation(int a, int b) = 0;
};
//add
class Product_Add : public Product{
public:
	int operation(int a, int b){
		return a + b;
	}
};
//mutiply
class Product_Mul : public Product{
public:
	int operation(int a, int b){
		return a * b;
	}
};
//factory
class Factory{
public:
	Product* Create(int i){
		switch (i){
		case 1:
			return new Product_Add;
			break;
		case 2:
			return new Product_Mul;
			break;
		default:
			break;
		}
	}
};

int main()
{
	Factory *factory = new Factory();
	int add_result = factory->Create(1)->operation(1, 2);
	int mul_result = factory->Create(2)->operation(1, 2);
	cout <<"op_add:" <<add_result << endl;
	cout <<"op_multiply:" << mul_result << endl;
	getchar();
	return 0;
}

工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码

  • 工厂方法模式
class Product{
public:
	virtual int operation(int a, int b) = 0;
};

class Product_Add : public Product{
public:
	int operation(int a, int b){
		return a + b;
	}
};

class Product_Mul : public Product{
public:
	int operation(int a, int b){
		return a * b;
	}
};

class Factory{
public:
	virtual Product* Create() = 0;
};


class Factory_Add : public Factory{
public:
	Product* Create(){
		return new Product_Add;
	}
};

class Factory_Mul : public Factory{
public:
	Product* Create(){
		return new Product_Mul;
	}
};

int main()
{
	Factory_Add *factory_add = new Factory_Add();
	Factory_Mul *factory_mul = new Factory_Mul();
	int add_result = factory_add->Create()->operation(1, 2);
	int mul_result = factory_mul->Create()->operation(1, 2);
	cout << "op_add:" << add_result << endl;
	cout << "op_multiply:" << mul_result << endl;
	getchar();
	return 0;
}

新增一个产品新增一个工厂

  • 抽象工厂模式

class Product_P{
public:
	virtual int operation(int a, int b) = 0;
};

class Product_Padd : public Product_P{
public:
	int operation(int a, int b){
		return abs(a) + abs(b);
	}
};

class Product_Pmul : public Product_P{
public:
	int operation(int a, int b){
		return abs(a) * abs(b);
		
	}
};

class Product_F{
public:
	virtual int operation(int a, int b) = 0;
};

class Product_Fadd : public Product_F{
public:
	int operation(int a, int b){
		return (-a) + (-b);
	}
};
class Product_Fmul : public Product_F{
public:
	int operation(int a, int b){
		return -(a*b);
	}
};

class Factory{
public:
	virtual Product_P* Create_P() = 0;
	virtual Product_F* Create_F() = 0;
};


class Factory_Add : public Factory{
public:
	  Product_Padd* Create_P(){
		return new Product_Padd;
	}
	Product_Fadd*  Create_F(){
		return new Product_Fadd;
	}
};

class Factory_Mul : public Factory{
public:
	Product_Pmul* Create_P(){
		return new Product_Pmul;
	}
	Product_Fmul* Create_F(){
		return new Product_Fmul;
	}
};

int main()
{
	Factory_Add *factory_add = new Factory_Add();
	Factory_Mul *factory_mul = new Factory_Mul();
	int p_add_result = factory_add->Create_P()->operation(1, 2);
	int p_mul_result = factory_mul->Create_P()->operation(1, 2);
	int f_add_result = factory_add->Create_F()->operation(1, 2);
	int f_mul_result = factory_mul->Create_F()->operation(1, 2);
	cout << "op_p_add:" << p_add_result << endl;
	cout << "op_p_multiply:" << p_mul_result << endl;
	cout << "op_f_add:" << f_add_result << endl;
	cout << "op_f_multiply:" << f_mul_result << endl;
	getchar();
	return 0;
}

简单工厂模式和工厂方法模式的组合,抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类
Merit:
1、一个调用者想创建一个对象,只要知道其名称就可以了
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以
3、屏蔽产品的具体实现,调用者只关心产品的接口
Design Methods:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事
Demerit:
1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方
2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时
3、设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口

(2)Observer pattern(观察者模式)

Features: 当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)
Example: 一个人拥有多个孩子,通知不同孩子做不同的事;一个公司有多个部门,通知部门
Design Methods:
人归家,通知两个孩子"Mike" 与 “Jane”

#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
using namespace std;

class  observer_interface
{
    public:
    virtual void feed_back()=0;
};

class subject_interface
{
public:
virtual void add(shared_ptr<observer_interface> obs)=0;
virtual void remove(shared_ptr<observer_interface> obs)=0;
virtual void notify()=0;
};

class people:public subject_interface
{
    public:
    void add(shared_ptr<observer_interface> obs)override
    {
        childs.push_back(obs);
    }
    void remove(shared_ptr<observer_interface> obs)override
    {
        auto temp=find(childs.begin(),childs.end(),obs);
        if (temp!=childs.end())
            childs.erase(temp);
    }
    void notify()
    {
        for(const auto& obs:childs){
            obs->feed_back();
        }
    }

    private:
    vector<shared_ptr<observer_interface>> childs;
} ;

class  Mike:public observer_interface
{
    public:
    void feed_back()override
    {
        cout<<"Stop play games, Go to do homework"<<endl;
    }

};

class  Jane:public observer_interface
{
    public:
    void feed_back()override
    {
        cout<<"Dad will come back home, so happy"<<endl;
    }

};

int main()
{
    shared_ptr<observer_interface> mike=make_unique<Mike>();
    shared_ptr<observer_interface> jane=make_unique<Jane>();
    people me;
    me.add(jane);
    me.add(mike);
    me.notify();
    return 0;
}

Merigt: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
**Demerigt:**1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

(3)Strategy Pattern

(R1)
Features:
定义一系列算法,一个客户在执行同一个方法时,可以选择不同算法;
Example:

  • 公司结账时,不同职位选择不同的策略;
    Design Methods:
    普通策略模式
#include <iostream>
using namespace std;

// The abstract strategy
class Strategy
{
public:
     virtual void AlgorithmInterface(int day) = 0;
};

class ConcreteStrategyA : public Strategy
{
public:
     void AlgorithmInterface(int day)
     {
        cout<<"Salary:"<<day*100+1000<<endl;
     }
};

class ConcreteStrategyB : public Strategy
{
public:
     void AlgorithmInterface(int day)
     {
         cout<<"Salary:"<<day*800+3000<<endl;
     }
};

class ConcreteStrategyC : public Strategy
{
public:
     void AlgorithmInterface(int day)
     {
        cout<<"Salary:"<<day*1600+27000<<endl;
     }
};

class Context
{
public:
     Context(Strategy *pStrategyArg) : pStrategy(pStrategyArg)
     {
     }
     void ContextInterface(int day)
     {
          pStrategy->AlgorithmInterface(day);
     }
private:
     Strategy *pStrategy;
};

int main()
{
     // Create the Strategy
     Strategy *pStrategyA = new ConcreteStrategyA;
     Strategy *pStrategyB = new ConcreteStrategyB;
     Strategy *pStrategyC = new ConcreteStrategyC;
     Context *pContextA = new Context(pStrategyA);
     Context *pContextB = new Context(pStrategyB);
     Context *pContextC = new Context(pStrategyC);
     pContextA->ContextInterface(28);
     pContextB->ContextInterface(25);
     pContextC->ContextInterface(30);

     if (pStrategyA) delete pStrategyA;
     if (pStrategyB) delete pStrategyB;
     if (pStrategyC) delete pStrategyC;
     
     if (pContextA) delete pContextA;
     if (pContextB) delete pContextB;
     if (pContextC) delete pContextC;
}

但上述方法实现太麻烦,可以借鉴简单工厂模式用if…else…选择

#include <iostream>
using namespace std;

// Define the strategy type
typedef enum StrategyType
{
    StrategyA,
    StrategyB,
    StrategyC
}STRATEGYTYPE;

// The abstract strategy
class Strategy
{
public:
    virtual void AlgorithmInterface() = 0;
    virtual ~Strategy() = 0; // 谢谢hellowei提出的bug,具体可以参见评论
};

Strategy::~Strategy()
{}

class ConcreteStrategyA : public Strategy
{
public:
    void AlgorithmInterface()
    {
        cout << "I am from ConcreteStrategyA." << endl;
    }

    ~ConcreteStrategyA(){}
};

class ConcreteStrategyB : public Strategy
{
public:
    void AlgorithmInterface()
    {
        cout << "I am from ConcreteStrategyB." << endl;
    }

    ~ConcreteStrategyB(){}
};

class ConcreteStrategyC : public Strategy
{
public:
    void AlgorithmInterface()
    {
        cout << "I am from ConcreteStrategyC." << endl;
    }

    ~ConcreteStrategyC(){}
};

class Context
{
public:
    Context(STRATEGYTYPE strategyType)
    {
        switch (strategyType)
        {
        case StrategyA:
            pStrategy = new ConcreteStrategyA;
            break;

        case StrategyB:
            pStrategy = new ConcreteStrategyB;
            break;

        case StrategyC:
            pStrategy = new ConcreteStrategyC;
            break;

        default:
            break;
        }
    }

    ~Context()
    {
        if (pStrategy) delete pStrategy;
    }

    void ContextInterface()
    {
        if (pStrategy)
            pStrategy->AlgorithmInterface();
    }

private:
    Strategy *pStrategy;
};

int main()
{
    Context *pContext = new Context(StrategyA);
    pContext->ContextInterface();

    if (pContext) delete pContext;
}

Merit:
1、算法可以自由切换
2、避免使用多重条件判断
3、扩展性良好

Demerit:
1、策略类会增多
2、所有策略类都需要对外暴露

(4)Template Method Pattern

Features:

  • 一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行
  • 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
  • 有一套固定流程的事件,而流程中可以选择不同的介质

Example:

  • 修房子时把管线都预留出来,后来加上自己想要的马桶,厨房,空调等

Design Methods:

#include <iostream>
#include <memory>
 
//简历
class Resume
{
protected: //保护成员
    virtual void SetPersonalInfo() {}
    virtual void SetEducation() {}
    virtual void SetWorkExp() {}
public:
    void FillResume()
    {
        SetPersonalInfo();
        SetEducation();
        SetWorkExp();
    }
};
 
class ResumeA: public Resume
{
protected:
    void SetPersonalInfo()
    {
        std::cout << "A's PersonalInfo" << std::endl;
    }
    void SetEducation()
    {
        std::cout << "A's Education" << std::endl;
    }
    void SetWorkExp()
    {
        std::cout << "A's Work Experience" << std::endl;
    }
};
 
class ResumeB: public Resume
{
protected:
    void SetPersonalInfo()
    {
        std::cout << "B's PersonalInfo" << std::endl;
    }
    void SetEducation()
    {
        std::cout << "B's Education" << std::endl;
    }
    void SetWorkExp()
    {
        std::cout << "B's Work Experience" << std::endl;
    }
};
 
int main()
{
    auto r1 = ResumeA();
    r1.FillResume();
 
    auto r2 = ResumeB();
    r2.FillResume();
 
    return 0;
}

Merit:
1、封装不变部分,扩展可变部分
2、提取公共代码,便于维护
3、行为由父类控制,子类实现
Demerit:
每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大

(5)Proxy Pattern

Features:

  • 为其他对象提供一种代理以控制对这个对象的访问
    Example:
  • 远程网络代理
  • 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理

Design Methods:


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



//Subject
class Network
{
public: 
    int  localIp;
    int subnetMask;
    int pin_result=0;
    void pin(int ip)
    {
        pin_result=(localIp&subnetMask)== (ip&subnetMask);
    }
    virtual int proxy_pin(int ip)=0;
};


//RealSubject
class Me :public Network
{
public:
    int proxy_pin(int ip){};
    Me()
    {
        localIp=0x12131311;
        subnetMask=0xffffff00;
    }

};

//Proxy
class Remote :public Network
{
public:
    Remote(Network *net) :OtherNet(net)
    {
        localIp=0x12131511;
        subnetMask=0xffffff00;
    }
    int proxy_pin(int ip)
    {
        pin(ip);
        OtherNet->pin_result=pin_result;
    }
private:
    Network *OtherNet;
};

//场景
int main()
{
    Network *me = new Me;
    Network *intermediary = new Remote(me);
    me->pin(0x12131512);
    cout<<me->pin_result<<endl;
    intermediary->proxy_pin(0x12131512);
    cout<<me->pin_result<<endl;
    return 0;
}

Merit:
1、职责清晰。 2、高扩展性。 3、智能化

Demerit:
1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂

(6)Summary

  • 单例模式:用于单个资源或者独一无二的对象,不可见内部
  • 工厂模式:用于高层通用接口,内部实现被封装
  • 观察者模式:存在一对多关系,一个对象做了某件事会影响其余多个对象
  • 策略模式:执行同一方法选择不同算法,自己定义策略
  • 模板方法模式:模板定义流程,细节选择自行填写
  • 代理模式:同类对象,帮助同类对象做其实现不了的功能

(7)Reference

R1: https://www.cnblogs.com/ring1992/p/9593575.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值