【设计模式】基于unique_ptr,工厂方法模式(又称虚拟构造器模式)

  1. 抽象类不能构建对象,因为类内含有纯虚函数,没有实现部分。(比如OBject是抽象类,不能通过Object obj来构建对象)
  2. 通常都是定义抽象类的指针或者引用,指向其派生类的对象的地址,对派生类中的成员进行操作。
  3. 但是,对于抽象类型来说,派生类在中仍然有一个隐藏基类对象,因为需要存放虚表指针,(虚表指针只有基类中有)
  4. 也就是不能产生具名对象,但是在派生类中有一个无名的隐藏基类对象。

问抽象类型有没有对象?

答:没有,不能直接调用构造函数创建具名对象,但是在继承关系中,在派生类中,仍然会调用基类的默认构造函数构建一个隐藏基类对象(无名对象)。(目的是存放虚表指针)

设计模式:
创建型设计模式:用于创建对象
结构性设计模式:用于处理类和对象的组合
行为型设计模式:用于描述类和对象如何交互和分配职责

工厂方法模式:

简单工厂模式的缺点:

在简单工厂模式中只提供一个工厂类,该工厂类处于对产品类进行实例化的中心位置它需要知道每一个产品对象的创建细节,并决定何时实例化哪一个产品类。
简单工厂模式最大的缺点当有新产品要加入到系统中时,必须修改工厂类,需要在其中加入必要的业务逻辑,这违背了“开闭原则”。
此外,在简单工厂模式中,所有的产品都由同一个工厂创建,工厂类职责较重,业务逻辑较为复杂,具体产品与工厂类之间的耦合度高,严重影响了系统的灵活性和扩展性,而工厂方法模式则可以很好地解决这一问题。

工厂方法模式

在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构。
简单来说:
工厂方法模式:

  1. 定义一个用于创建对象的接口,让子类决定将哪一个类实例化。
  2. 工厂方法模式让一个类的实例化延迟到其子类。
    工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。

工厂方法模式的角色

抽象产品:
关系:具体产品类的基类
作用:描述具体产品的公共接口。
具体产品:
关系:抽象产品的派生类,工厂类创建的目标类(具体工厂和具体产品一一对应)
作用:描述生产的具体产品
抽象工厂:
关系:具体工厂的基类
作用:声明了工厂方法,用于返回一个产品,抽象工厂是工厂模式的核心,所有创建对象的工厂类都必须实现该接口。
具体工厂:
关系:抽象工厂的派生类,被外界调用
作用:描述具体工厂,创建产品的实例,并可由客户端调动返回一个具体的产品类实例。
与简单工厂相比,工厂模式最重要的区别就是引入了抽象工厂的角色,抽象工厂可以是接口,也可以是抽象类或者具体类。

日志记录器:

日志记录器的设计有两个要点:
1.需要封装日志记录器的初始化过程。这些初始化工作较为复杂,例如需要初始化其他相关的类,还有可能需要读取配置文件(例如数据库和创建文件),导致代码较长,如果将他们都写在构造函数中,会导致构造函数特别庞大,不利于代码的修改和维护。
2.用户可能需要更换日志记录方式,在客户端代码中需要提供一种灵活的方式来选择日志记录器,尽量在不修改源代码的基础上更换或者增加日志记录的方式。
请添加图片描述
请添加图片描述

1. 抽象产品类:日志记录器接口:

struct Logger
{
    virtual void writeLog() = 0;
    Logger() { cout << "日志记录器接口" << endl; }
   //能够重置虚表指针
    virtual ~Logger() { cout << "~Logger" << endl; }
};

2. 具体产品:数据库日志记录器

class DatabaseLogger : public Logger
{
public:
    DatabaseLogger() { cout << "DatabaseLogger()" << endl; }
    ~DatabaseLogger() { cout << "~DatabaseLogger()" << endl; }

    void writeLog()
    {
        cout << "数据库日志记录" << endl;
    }
};

3. 具体产品:文件日志记录器

class FileLogger :public Logger
{
public:
    FileLogger() { cout << "FileLogger()" << endl; }
    ~FileLogger() { cout << "~FileLogger()" << endl; }
    
    void writeLog()
    {
        cout << "文件日志记录" << endl;
    }
};

4.抽象工厂类:日志记录器工厂接口

struct LoggerFactory
{
    virtual my_unique_ptr<Logger> createLogger() = 0;
    LoggerFactory() { cout << "LoggerFactory()" << endl; }
    virtual ~LoggerFactory() {cout << "~LoggerFactory()"<<endl;}
};

5. 具体工厂:数据库日志记录器工厂类

class DatabaseLoggerFactory:public LoggerFactory
{
public:
    DatabaseLoggerFactory() { cout << "DatabaseLoggerFactory()" << endl; }
    ~DatabaseLoggerFactory() { cout << "~DatabaseLoggerFactory()" << endl; }
    my_unique_ptr<Logger> createLogger()
    {
        return my_unique_ptr<Logger>(new DatabaseLogger());
    }
};

6. 具体工厂:文件日志记录器工厂类

class FileLoggerFactory :public LoggerFactory
{
public:
   FileLoggerFactory() { cout << "FileLoggerFactory()" << endl; }
    ~FileLoggerFactory() { cout << "~FileLoggerFactory()" << endl; }
    my_unique_ptr<Logger> createLogger()
    {
        return my_unique_ptr<Logger>(new FileLogger());
    }
};

测试:

int main()
{
    //使用文件日志工厂
    my_unique_ptr<LoggerFactory>factory(new DatabaseLoggerFactory());
    my_unique_ptr<Logger>logger = factory->createLogger();  //返回创建具体产品的对象的地址
    logger->writeLog();
    factory.reset(new FileLoggerFactory);
    logger = factory->createLogger();
    logger->writeLog();

}

请添加图片描述

总结:

工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时还弥补了简单工厂模式的不足。工厂方法模式是使用频率最高的设计模式之一,是很多开源框架和API类库的核心模式。

在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责哪一个产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。

1.优点

  1. 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
  2. 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,就正是因为所有的具体工厂类都具有同一抽象父类。
  3. 另外在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。

2. 缺点

  1. 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
  2. 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

3.适用场景

  1. 客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建,可将具体工厂类的类名存储在配置文件或数据库中。
  2. 抽象工厂类通过其子类来指定创建哪个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

完整代码:

my_unique_ptr

#pragma once
#include<iostream>
using namespace std;
template<typename _Ty>
class myDeletor
{
public:
	myDeletor() = default;
	void operator()(_Ty* ptr) const
	{
		if (ptr != nullptr)
		{
			delete ptr;
		}
	}
};

template<typename _Ty>
class myDeletor<_Ty[]>
{
public:
	myDeletor() = default;

	void operator()(_Ty* ptr) const
	{
		if (ptr != nullptr)
		{
			delete[]ptr;
		}
	}
};

// my_unique_ptr
template<typename _Ty, typename _Dx = myDeletor<_Ty> >
class my_unique_ptr
{
public:
	using pointer = _Ty*;
	using element_type = _Ty;
	using delete_type = _Dx;

private:
	pointer _Ptr;
	delete_type _myDeletor;

public:
	my_unique_ptr(const my_unique_ptr& _Y) = delete;
	my_unique_ptr operator =(const my_unique_ptr& _Y) = delete;

	my_unique_ptr(pointer _P = nullptr)
		: _Ptr(_P)
	{
		cout << "my_unique_ptr: " << this << endl;
	}

	~my_unique_ptr() {
		if (_Ptr != nullptr) {
			_myDeletor(_Ptr);
			_Ptr = nullptr;
		}
		cout << "~my_unique_ptr: " << this << endl;
	}

	_Dx& get_deletor() {
		return _myDeletor;
	}
	const _Dx& get_deletor() const {
		return _myDeletor;
	}

	pointer get_pointer() const {
		return _Ptr;
	}

	operator bool() {
		return _Ptr != nullptr;
	}

	_Ty& operator*() const {
		return *_Ptr;
	}

	pointer operator->() const {
		return &**this;
	}

	pointer release() {
		pointer old = _Ptr;
		_Ptr = nullptr;

		return old;
	}

	void reset(pointer _P = nullptr) {
		pointer old = _Ptr;
		_Ptr = _P;

		if (old != nullptr) {
			_myDeletor(old);
			// get_deletor()(old);
		}
	}

	void Swap(my_unique_ptr _Y) {
		std::swap(_Ptr, _Y._Ptr);
		std::swap(_myDeletor, _Y._myDeletor);
	}

	my_unique_ptr(my_unique_ptr&& _Y) {
		_Ptr = _Y._Ptr;
		_Y = nullptr;
	}

	my_unique_ptr& operator=(my_unique_ptr&& _Y) {
		if (this == &_Y) {
			return *this;
		}

		reset(_Y.release());
		return *this;
	}

};

// array
template<typename _Ty, typename _Dx>
class my_unique_ptr<_Ty[], _Dx>
{
public:
	using pointer = _Ty*;
	using element_type = _Ty;
	using delete_type = _Dx;

private:
	pointer _Ptr;
	delete_type _myDeletor;

public:
	my_unique_ptr(const my_unique_ptr& _Y) = delete;
	my_unique_ptr operator =(const my_unique_ptr& _Y) = delete;

	my_unique_ptr(pointer _P = nullptr)
		: _Ptr(_P)
	{
		cout << "my_unique_ptr: " << this << endl;
	}

	~my_unique_ptr() {
		if (_Ptr != nullptr) {
			_myDeletor(_Ptr);
			_Ptr = nullptr;
		}
		cout << "~my_unique_ptr: " << this << endl;
	}

	_Dx& get_deletor() {
		return _myDeletor;
	}
	const _Dx& get_deletor() const {
		return _myDeletor;
	}

	pointer get_pointer() const {
		return _Ptr;
	}

	operator bool() {
		return _Ptr != nullptr;
	}

	_Ty& operator*() const {
		return *_Ptr;
	}

	pointer operator->() const {
		return &**this;
	}

	pointer release() {
		pointer old = _Ptr;
		_Ptr = nullptr;

		return old;
	}

	void reset(pointer _P = nullptr) {
		pointer old = _Ptr;
		_Ptr = _P;

		if (old != nullptr) {
			_myDeletor(old);
			// get_deletor()(old);
		}
	}

	void Swap(my_unique_ptr _Y) {
		std::swap(_Ptr, _Y._Ptr);
		std::swap(_myDeletor, _Y._myDeletor);
	}

	my_unique_ptr(my_unique_ptr&& _Y) {
		_Ptr = _Y._Ptr;
		_Y = nullptr;
	}

	my_unique_ptr& operator=(my_unique_ptr&& _Y) {
		if (this == &_Y) {
			return *this;
		}

		reset(_Y.release());
		return *this;
	}

	_Ty& operator[](size_t _Idx) const {
		return _Ptr[_Idx];
	}
};

template<typename _Ty, typename ... _Type>
my_unique_ptr<_Ty> my_make_unique(_Type&& ... _args)
{
	return my_unique_ptr<_Ty>(new _Ty(_args...));
}
#include<iostream>
#include "my_unique_ptr.h"
using namespace std;
//抽象产品类:日志记录器接口
struct Logger
{
    virtual void writeLog() = 0;
    Logger() { cout << "日志记录器接口" << endl; }
   //能够重置虚表指针
    virtual ~Logger() { cout << "~Logger" << endl; }
};
//具体产品:数据库日志记录器
class DatabaseLogger : public Logger
{
public:
    DatabaseLogger() { cout << "DatabaseLogger()" << endl; }
    ~DatabaseLogger() { cout << "~DatabaseLogger()" << endl; }

    void writeLog()
    {
        cout << "数据库日志记录" << endl;
    }
};
//具体产品:文件日志记录器
class FileLogger :public Logger
{
public:
    FileLogger() { cout << "FileLogger()" << endl; }
    ~FileLogger() { cout << "~FileLogger()" << endl; }
    
    void writeLog()
    {
        cout << "文件日志记录" << endl;
    }
};

//抽象工厂:日志记录器工厂接口
struct LoggerFactory
{
    virtual my_unique_ptr<Logger> createLogger() = 0;
    LoggerFactory() { cout << "LoggerFactory()" << endl; }
    virtual ~LoggerFactory() { cout << "~LoggerFactory()"<<endl;}
};
//具体工厂:数据库日志记录器工厂类
class DatabaseLoggerFactory:public LoggerFactory
{
public:
    DatabaseLoggerFactory() { cout << "DatabaseLoggerFactory()" << endl; }
    ~DatabaseLoggerFactory() { cout << "~DatabaseLoggerFactory()" << endl; }
    my_unique_ptr<Logger> createLogger()
    {
        return my_unique_ptr<Logger>(new DatabaseLogger());
    }
};
class FileLoggerFactory :public LoggerFactory
{
public:
     FileLoggerFactory() { cout << "FileLoggerFactory()" << endl; }
    ~FileLoggerFactory() { cout << "~FileLoggerFactory()" << endl; }
    my_unique_ptr<Logger> createLogger()
    {
        return my_unique_ptr<Logger>(new FileLogger());
    }
};
int main()
{
    //使用文件日志工厂
    my_unique_ptr<LoggerFactory>factory(new DatabaseLoggerFactory());
    my_unique_ptr<Logger>logger = factory->createLogger();  //返回创建具体产品的对象的地址
    logger->writeLog();
    factory.reset(new FileLoggerFactory);
    logger = factory->createLogger();
    logger->writeLog();

}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值