设计模式(一)

什么是设计模式:

软件领域中的设计模式为开发人员提供了一种使用根据以往专家在软件开发过程中面临问题总结得通用问题的解决方案有效途径。设计模式中运用了面向对象编程语言的重要特性:封装、继承、多态。这些解决方案使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

设计模式的分类:

总体来说设计模式分为三大类:

|----------|---------------------------------------------|------------------------------------------------------------------|
| 模式类型 | 目的 | 模式举例 |
| 创建型模式 | 用于创建对象,隔离、封装变化:new的解耦 | 工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式 |
| 结构型模式 | 主要用于处理类或对象的组合,隔离、封装变化:类内部结构、对象之间结构的解耦 | 适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 |
| 行为型模式 | 用于描述对类或对象怎样交互和怎样分配职责,隔离、封装变化,将动作封装成对象从类中解耦。 | 策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 |

设计模式详解:

1、工厂模式:

1、1 简单工厂模式

一个工厂类根据传入的参量决定创建出哪一种产品类的实例,简单工厂模式最大的优点在于工厂类中包含了必要的逻辑判断,根据用户选择的条件动态实例化相关的类,对客户端来说,去除了与具体产品的依赖,但是缺点是当需求变动的时候,需要对原有的类进行修改,违反了开放封闭原则

简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>
#include <limits>

class operation_base
{
public:
	virtual ~operation_base() = default;

	virtual double GetResult(double operation_a, double operation_b) const = 0;
};

class operation_add : public operation_base
{
	virtual double GetResult(double operation_a, double operation_b) const override
	{
		return operation_a + operation_b;
	}
};

class operation_subtract : public operation_base
{
	virtual double GetResult(double operation_a, double operation_b) const override
	{
		return operation_a - operation_b;
	}
};

class operation_mutiply : public operation_base
{
	virtual double GetResult(double operation_a, double operation_b) const override
	{
		return operation_a * operation_b;
	}
};

class operation_division : public operation_base
{
	virtual double GetResult(double operation_a, double operation_b) const override
	{
		if (operation_b == 0)
			throw std::overflow_error("Divide by zero exception");

		return operation_a / operation_b;
	}
};

std::unique_ptr<operation_base> GetOperation(char operation_symbol)
{
	std::unique_ptr<operation_base> operation_base(nullptr);
	switch (operation_symbol)
	{
	case '+':
	{
		operation_base = std::make_unique<operation_add>();
	}
	break;
	case '-':
	{
		operation_base = std::make_unique<operation_subtract>();
	}
	break;
	case '*':
	{
		operation_base = std::make_unique<operation_mutiply>();
	}
	break;
	case '/':
	{
		operation_base = std::make_unique<operation_division>();
	}
	break;
	default:
	{
		// 不支持的运算符
	}
	break;
	}

	return operation_base;
}
void check(double &d)
{
	while (true)
	{
		std::cin >> d;
		if (std::cin.fail())
		{
			std::cin.clear(); // 清除错误标志
			std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
			std::cout << "非法输入,请确保输入为整数并再次尝试。\n";
			std::cout << "请输入一个合法数: ";
			continue;
		}
		break;
	}
}
int main()
{
	double operation_a = 0.0;
	double operation_b = 0.0;
	char operation_symbol = 0;
	std::unique_ptr<operation_base> operation_base;
	while (true)
	{

		std::cout << "请输入第一个数:";
		check(operation_a);
		std::cout << "请输入第二个数:";
		check(operation_b);
		std::cout << "请输入运算符(+, -, *, /):";
		std::cin >> operation_symbol;
		operation_base = GetOperation(operation_symbol);
		if (operation_base == nullptr)
		{
			std::cout << "输入了不支持的运算符\n";
		}
		else
		{
			try
			{
				std::cout << "结果为:" << operation_base->GetResult(operation_a, operation_b) << "\n";
			}
			catch (const std::overflow_error &e)
			{
				std::cerr << "Caught a divide by zero exception: " << e.what() << std::endl;
			}
		}
		std::cout << "算式处理完成\n\n"<< std::flush;
	}
	return 0;
}
1、2 工厂方法:

定义一个创建对象的接口,让子类决定实例化那个类。工厂方法把类的实例化推迟到子类,使用到了多态。当需要增加一个新的产品时,我们需要增加一个具体的产品类和与之对应的具体子工厂,然后在具体子工厂方法中进行对象实例化,所以称为工厂方法模式。它克服了简单工厂违背的开放封闭原则。(具体现实的例子比如不管你去麦当劳或肯德基,只管向服务员说"一个汉堡"就行了。麦当劳和肯德基就是生产汉堡的Factory工厂模式:客户类和工厂类分开,消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供)

cpp 复制代码
#include <iostream>
#include <memory>

class operation
{
public:
	virtual ~operation() = default;
	virtual double CalculateOperation(double operation_a, double operation_b)const = 0;
};

class operation_Add : public operation
{
public:
	virtual double CalculateOperation(double operation_a, double operation_b)const override
	{
		return operation_a + operation_b;
	}
};

class operation_Sub : public operation
{
public:
	virtual double CalculateOperation(double operation_a, double operation_b)const override
	{
		return operation_a - operation_b;
	}
};

class operation_Mul : public operation
{
public:
	virtual double CalculateOperation(double operation_a, double operation_b)const override
	{
		return operation_a * operation_b;
	}
};

class operation_Div : public operation
{
public:
	virtual double CalculateOperation(double operation_a, double operation_b)const override
	{
		return operation_a / operation_b;
	}
};
//工厂方法
class operation_Factory
{
public:
	virtual ~operation_Factory() = default;
	virtual std::unique_ptr<operation> GetOperator()const = 0;
};

class operation_FactoryAdd : public operation_Factory
{
public:
	virtual std::unique_ptr<operation> GetOperator()const override
	{
		return std::make_unique<operation_Add>();
	}
};

class operation_FactorySub : public operation_Factory
{
public:
	virtual std::unique_ptr<operation> GetOperator()const override
	{
		return std::make_unique<operation_Sub>();
	}
};

class operation_FactoryMul : public operation_Factory
{
public:
	virtual std::unique_ptr<operation> GetOperator()const override
	{
		return std::make_unique<operation_Mul>();
	}
};

class operation_FactoryDiv : public operation_Factory
{
public:
	virtual std::unique_ptr<operation> GetOperator()const override
	{
		return std::make_unique<operation_Div>();
	}
};
int main()
{
	std::unique_ptr<operation_Factory> upFactory = std::make_unique<operation_FactoryAdd>();
	std::unique_ptr<operation> up = upFactory->GetOperator();
	std::cout << up->CalculateOperation(1, 2) << std::endl;
	return 0;
}
1、3 抽象工厂方法:

为创建一组相关或相互依赖的对象提供一个接口,而且无须指定他们的具体类。优点:在有多个业务品种、业务分类时,通过抽象工厂模式生产需要的对象是一个非常好的解决方式。缺点:加入产品族中要加入一个新的产品,不仅要实现产品类,还有创建相关的工厂接口。

cpp 复制代码
#include <iostream>
#include <memory>

class operation
{
public:
	virtual ~operation() = default;
	virtual double CalculateOperation(double operation_a, double operation_b)const = 0;
};
class operation_Add : public operation
{
public:
	virtual double CalculateOperation(double operation_a, double operation_b)const override
	{
		return operation_a + operation_b;
	}
};
class operation_Sub : public operation
{
public:
	virtual double CalculateOperation(double operation_a, double operation_b)const override
	{
		return operation_a - operation_b;
	}
};
//一个不同的计算器
class operation1
{
public:
	virtual ~operation1() = default;
	virtual double CalculateOperation1(double operation_a, double operation_b)const = 0;
};
class operation_Add1 : public operation1
{
public:
	virtual double CalculateOperation1(double operation_a, double operation_b)const override
	{
		return operation_a + operation_b;
	}
};
class operation_Sub1 : public operation1
{
public:
	virtual double CalculateOperation1(double operation_a, double operation_b)const override
	{
		return operation_a - operation_b;
	}
};

//抽象工厂方法:两种计算器都可以生成给客户端提供一个接口,创建不同产品族种的不同产品,对多个业务品种,
//业务分类时通过抽象工厂模式生产需要的对象时一个非常好的解决方式
//缺点是加入产品族中加入一个新的产品时不仅要实现产品类还要创建相关的工厂接口
class operation_Factory
{
public:
	virtual ~operation_Factory() = default;
	virtual std::unique_ptr<operation> GetOperator()const = 0;
	virtual std::unique_ptr<operation1> GetOperator1()const = 0;
};

class operation_FactoryAdd : public operation_Factory
{
public:
	virtual std::unique_ptr<operation> GetOperator()const override
	{
		return std::make_unique<operation_Add>();
	}
		virtual std::unique_ptr<operation1> GetOperator1()const override
	{
		return std::make_unique<operation_Add1>();
	}
};

class operation_FactorySub : public operation_Factory
{
public:
	virtual std::unique_ptr<operation> GetOperator()const override
	{
		return std::make_unique<operation_Sub>();
	}
		virtual std::unique_ptr<operation1> GetOperator1()const override
	{
		return std::make_unique<operation_Sub1>();
	}
};
int main()
{
	std::unique_ptr<operation_Factory> addFactory = std::make_unique<operation_FactoryAdd>();
	std::unique_ptr<operation> add = addFactory->GetOperator();
	std::unique_ptr<operation1> add1 = addFactory->GetOperator1();
	std::cout << add->CalculateOperation(1, 2) << std::endl;
	std::cout << add1->CalculateOperation1(1, 2) << std::endl;
	std::unique_ptr<operation_Factory> subFactory = std::make_unique<operation_FactorySub>();
	std::unique_ptr<operation> sub = subFactory->GetOperator();
	std::unique_ptr<operation1> sub1 = subFactory->GetOperator1();
	std::cout << sub->CalculateOperation(1, 2) << std::endl;
	std::cout << sub1->CalculateOperation1(1, 2) << std::endl;
	return 0;
}

2、单例模式

单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

应用:单例模式主要作用是确保一个类只有一个实例存在。单例模式可以用在建立目录、数据库连接等需要单线程操作的场合,用于实现对系统资源的控制。

1、懒汉单例模式

定义:第一次引用类时,才进行对象实例化,实现时有非线程安全的懒汉单例模式和线程安全的懒汉模式

cpp 复制代码
#include <iostream>
#include <mutex>
std::mutex mt;
class Singleton
{
    
public:
    static Singleton *GetInstance();
    ~Singleton(){};

private:
    Singleton() = default;
    Singleton(const Singleton &obj) = delete; // 明确拒绝
    Singleton &operator=(const Singleton &obj) = delete;
    static Singleton *sm_instance;//静态成员变量必须类外初始化,只有一个
};
//懒汉模式
Singleton *Singleton::sm_instance = nullptr;
Singleton *Singleton::GetInstance()
{
    // 非线程安全的懒汉单例模式
    // if (sm_instance == nullptr)
    // {
    //     sm_instance = new Singleton();
    // }
    //线程安全的懒汉单例模式代码(加了把锁,访问静态变量变成了原子操作)
    if (sm_instance == nullptr)
    {
        mt.lock();
        if (sm_instance == nullptr)
        {
            sm_instance = new Singleton();
        }
        mt.unlock();
    }
    return sm_instance;
}
int main()
{
    Singleton *a = Singleton::GetInstance();
    Singleton *b = Singleton::GetInstance();
    if (a == b)
    {
        std::cout << "same" << std::endl;
    }
    return 0;
}

2、饿汉单例模式

cpp 复制代码
#include <iostream>
class Singleton
{
    
public:
    static Singleton *GetInstance();
    ~Singleton(){};

private:
    Singleton() = default;
    Singleton(const Singleton &obj) = delete; // 明确拒绝
    Singleton &operator=(const Singleton &obj) = delete;
    static Singleton *sm_instance;//静态成员变量必须类外初始化,只有一个
};

//饿汉模式 定义:类加载时,就进行对象实例化不管用不用得到,都构造出来。本身就是线程安全的
Singleton* Singleton::sm_instance = new Singleton();
//类外定义,main开始执行前,该对象就存在了
Singleton* Singleton::GetInstance()
{
    return sm_instance;
}
int main()
{
    Singleton *a = Singleton::GetInstance();
    Singleton *b = Singleton::GetInstance();
    if (a == b)
    {
        std::cout << "same" << std::endl;
    }
    return 0;
}

3、建造者模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

应用场景:相同的方法,不同的执行顺序会产生不同的结果时可以使用建造者模式;多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同; 产品类非常复杂,或者产品类中的方法调用顺序不同产生了不同的效能,使用建造者模式。

cpp 复制代码
#include <iostream>
#include <memory>

class Builder
{
public:
	virtual ~Builder() = default;
	virtual void BuilderPartA()const = 0;
	virtual void BuilderPartB()const = 0;
};

class ConcreteBuilderA : public Builder
{
public:
	virtual void BuilderPartA()const
	{
		std::cout << "BuilderPartA"<<std::endl;
	}

	virtual void BuilderPartB()const
	{
		std::cout << "BuilderPartB"<<std::endl;
	}
};

class ConcreteBuilderB : public Builder
{
public:
	virtual void BuilderPartA()const
	{
		std::cout << "Anther BuilderPartA ";
	}
	virtual void BuilderPartB()const
	{
		std::cout << "Anther BuilderPartB";
	}
};
class Director
{
public:
	explicit Director(Builder *pb)
		: mb(pb)
	{
	}
	void Build()const
	{
		mb->BuilderPartA();
		mb->BuilderPartB();
	}
private:
	std::unique_ptr<Builder> mb = nullptr;
};
int main()
{
	Director dta(new ConcreteBuilderA());
	dta.Build();
    std::cout<<"----------------"<<std::endl;
	Director dtb(new ConcreteBuilderB());
	dtb.Build();
	return 0;
}

4、原型模式

定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

特点:类初始化需要消化非常多的资源,通过new产生一个对象需要非常繁琐的数据准备或者访问权限,可以使用原型模式提高性能;

原型模式提供了一个通过已存在对象进行新对象创建,C++里通过拷贝构造实现,拷贝又分为浅拷贝和深拷贝。浅拷贝 :将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。深拷贝:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。

cpp 复制代码
#include <iostream>
#include <string>
#include <memory>

struct WorkExperience
{
	std::string candidateWorkDate;
	std::string formerCompany;
};

class candidate
{
public:
	explicit candidate(const std::string &name)
		: candidateName(name)
	{
		jobWorkExperience = std::make_shared<WorkExperience>();
	}
    //如果自己实现这个拷贝构造,使用默认合成的拷贝构造,则工作经验就不会是想要的结果
	candidate(const candidate &other)
	{
		this->candidateName = other.candidateName;
		this->candidateSex = other.candidateSex;
		this->candidateAge = other.candidateAge;
		jobWorkExperience = std::make_shared<WorkExperience>(*other.jobWorkExperience);
	}

	void SetPersonalInfo(const std::string &sex, const std::string &age)
	{
		candidateSex = sex;
		candidateAge = age;
	}

	void SetWorkExperience(const std::string &workdDate, const std::string &company)
	{
		jobWorkExperience->candidateWorkDate = workdDate;
		jobWorkExperience->formerCompany = company;
	}

	void Display()const
	{
		std::cout << "姓名: "<<candidateName << " 性别: " << candidateSex << " 年龄: " << candidateAge << std::endl;
		std::cout << "工作经历:" << jobWorkExperience->candidateWorkDate << " 就职于 " << jobWorkExperience->formerCompany << std::endl;
	}

private:
	std::string candidateName;
	std::string candidateSex;
	std::string candidateAge;
	std::shared_ptr<WorkExperience> jobWorkExperience = nullptr;
};

int main()
{
	candidate candidateA("小明");
	candidateA.SetPersonalInfo("男", "28");
	candidateA.SetWorkExperience("2017-2018", "联通公司");

	candidate candidateB(candidateA);
	candidateB.SetWorkExperience("2019-2020", "电信公司");

	candidate candidateC(candidateA);
	candidateC.SetWorkExperience("2020-至今", "移动公司");

	candidateA.Display();
	candidateB.Display();
	candidateC.Display();

	return 0;
}
相关推荐
易只轻松熊22 分钟前
C++(21):fstream的读取和写入
开发语言·c++
重生之后端学习25 分钟前
02-前端Web开发(JS+Vue+Ajax)
java·开发语言·前端·javascript·vue.js
zimoyin26 分钟前
kotlin Android AccessibilityService 无障碍入门
android·开发语言·kotlin
繁依Fanyi1 小时前
用 CodeBuddy 实现「IdeaSpark 每日灵感卡」:一场 UI 与灵感的极简之旅
开发语言·前端·游戏·ui·编辑器·codebuddy首席试玩官
duapple5 小时前
Golang基于反射的ioctl实现
开发语言·后端·golang
Dxy12393102165 小时前
Python 条件语句详解
开发语言·python
prinrf('千寻)7 小时前
MyBatis-Plus 的 updateById 方法不更新 null 值属性的问题
java·开发语言·mybatis
m0_555762908 小时前
Qt缓动曲线详解
开发语言·qt
揽你·入怀9 小时前
数据结构:ArrayList简单实现与常见操作实例详解
java·开发语言
AA-代码批发V哥9 小时前
Math工具类全面指南
java·开发语言·数学建模