创造型模式3——工厂模式

前言

简单工厂模式虽然简单,但存在一个很严重的问题。当系统中需要引入新产品时,由于静态工厂方法通过所传入参数的不同来创建不同的产品,这必定要修改工厂类的源代码,将违背“开闭原则”,如何实现增加新产品而不影响已有代码?工厂方法模式应运而生,下面将介绍第二种工厂模式——工厂方法模式。

背景

日志记录器的设计

Sunny软件公司欲开发一个系统运行日志记录器(Logger),该记录器可以通过多种途径保存系统的运行日志,如通过文件记录或数据库记录,用户可以通过修改配置文件灵活地更换日志记录方式。在设计各类日志记录器时,Sunny公司的开发人员发现需要对日志记录器进行一些初始化工作,初始化参数的设置过程较为复杂,而且某些参数的设置有严格的先后次序,否则可能会发生记录失败。如何封装记录器的初始化过程并保证多种记录器切换的灵活性是Sunny公司开发人员面临的一个难题。

两个设计要点:

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

以下是使用简单工厂模式设计的日志记录器创造型模式3——工厂模式_第1张图片

工厂模式

定义

工厂方法模式:定义一个创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
创造型模式3——工厂模式_第2张图片
在工厂模式中包含以下几个角色:

  1. Product(抽象产品):它是定义产品的接口,是工厂模式所创建对象的超类型,也是产品对象的公共父类
  2. ConcreateProduct(具体产品):它实现了抽象产品的接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间以一一对应。
  3. Factory(抽象工厂):在抽象工厂类中,声明了工厂方法,用于返回一个产品,抽象工厂是工厂方法的核心,所有创建独享的工厂类都必须实现该接口。
  4. ConcreateFactory(具体工厂):它是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户端调用,返回一个具体产品类的实例。

与简单工厂模式相比,工厂方法模式最重要的区别是引入了抽象工厂角色,抽象工厂可以是接口,也可以是抽象类或者具体类,其典型代码如下所示:

//日志记录器接口
struct Logger
{
    virtual void writelog() = 0;
};

//数据库日志记录器:具体产品
class DatabaseLogger:public Logger
{
public:
    void writelog()
    {
        cout<<"数据库日志记录。"<<endl;
    }
};

//文件日志记录器:具体产品
class FileLogger:public Logger
{
public:
    void writelog()
    {
        cout<<"文件日志记录。"<<endl;
    }
};

//日志记录器工厂接口:抽象工厂
struct LoggerFactory
{
    virtual Logger* createLogger() = 0;
};

//数据库日志记录器工厂类:具体工厂
class DatabaseLoggerFactory:public LoggerFactory
{
public:
    Logger* createLogger()
    {
        //连接数据库代码省略
        //创建数据库日志记录对象
        Logger* logger = new DatabaseLogger();
        //初始化数据库日志记录器,代码省略
        return logger;
    }
};

//文件日志记录器工厂类:具体工厂
class FileLoggerFactory:public LoggerFactory
{
public:
    Logger* createLogger()
    {
        //连接数据库代码省略
        //创建数据库日志记录对象
        Logger* logger = new FileLogger();
        //初始化数据库日志记录器,代码省略
        return logger;
    }
};

int main()
{
    LoggerFactory* factory = new FileLoggerFactory();
    Logger* logger = factory->createLogger();
    logger->writelog();

    factory = new DatabaseLoggerFactory();
    logger = factory->createLogger();
    logger->writelog();
}

虽然实现了上述的工厂模式,但是其中的对象资源好像并没有得到很好的管理,于是我们利用之前智能指针进行管理。得到了下面的版本:

struct Logger
{
    virtual void writelog() = 0;
    //抽象类虽然不可以实例化对象,但可以作为无名隐藏基对象存在于子类中
    Logger(){cout<<"日志记录器接口"<<endl;}
    ~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;
};

//数据库日志记录器工厂类:具体工厂
class DatabaseLoggerFactory:public LoggerFactory
{
public:
    DatabaseLoggerFactory(){cout<<"DatabaseLoggerFactory"<<endl;}
    ~DatabaseLoggerFactory(){cout<<"~DatabaseLoggerFactory"<<endl;}
    my_unique_ptr<Logger> createLogger()
    {
        //连接数据库代码省略
        //创建数据库日志记录对象
        //Logger* logger = new DatabaseLogger();
        //初始化数据库日志记录器,代码省略
        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()
    {
        //连接数据库代码省略
        //创建数据库日志记录对象
        //Logger* logger = new FileLogger();
        //初始化数据库日志记录器,代码省略
        return my_unique_ptr<Logger> (new FileLogger());
    }
};

int main()
{
   my_unique_ptr<LoggerFactory> factory (new FileLoggerFactory());
   my_unique_ptr<Logger> logger = factory->createLogger();
   logger->writelog();

   factory.reset(new DatabaseLoggerFactory());
   logger = factory->createLogger();
   logger->writelog();
}

你可能感兴趣的:(设计模式)