1.什么是创建型模式

创建型模式顾名思义,是一种专注于类的实例化过程的设计模式,它的目标是将创建对象和使用对象的代码分离。外界只需要知道可以通过一组接口来获取对象,而不用关心具体是如何实现的

创建型模式主要以工厂模式为主,这也是本文研究的重心

2.简单工厂模式

想象有一组按钮ButtonA,ButtonB... ...,他们继承自相同的基类Button,实现了规定的接口。简单工厂模式会提供一个类来创建这些按钮的实例,接口调用者只需要提供不同的参数,就可以获得不同的实例

类图如下所示

部分实现代码如下

Factory.cpp

#include "Factory.h"
#include "ButtonA.h"
#include "ButtonB.h"
Factory::Factory(){}
Factory::~Factory(){}
Button* Factory::createButton(string bname)
{
    if(bname=="A")
        return new ButtonA();
    else if(bname=="B")
        return new ButtonB();
    return NULL;
}

main.cpp

int main(int argc, char** argv) {
    Button* b=Factory::createButton("B");
    b->showType();
    delete b;
    return 0;
}

3.简单工厂模式的优缺点和适用场景

优点:

①对象的创建和使用完全分开了,耦合度低。接口的调用者只需要简单的填入参数,由工厂类进行逻辑判断和创建对象

②比较灵活,增加新类或修改、替换类,无需改动接口调用者的代码

缺点:

①工厂类的职责重,出现错误很显然会影响整个系统

②增加新类或替换类需要改动工厂类的逻辑,违背开闭原则

③随着类的增长,工厂类内部的逻辑判断也会越来越复杂

简单工厂模式对接口调用者来说使用方便,很适合要创建的类种类较少的情况,JDK类库中广泛使用了简单工厂模式。

4.简单工厂模式改进:工厂方法模式

在简单工厂模式中,我们利用了Button的多态,通过Button类型的返回值来得到不同的实例,通过统一实现的接口进行使用

现在把多态引入工厂类就可以对简单工厂模式进行改进:创建一个抽象的工厂类,规定接口,由具体的工厂子类来实现接口,创建具体的对象。用户只需要知道对象对应的工厂子类即可

类图如下

对应代码如下

FactoryA.cpp

#include "Factory.h"
#include "ButtonA.h"
FactoryA::FactoryA(){}
FactoryA::~FactoryA(){}
Button* FactoryA::createButton()
{
        return new ButtonA();
}

main.cpp

#include <iostream>
#include "Button.h"
#include "FactoryB.h"
using namespace std;

int main(int argc, char** argv) {
    FactoryB* f=new FactoryB()
    Button* b=f->createButton();
    b->showType();
    delete b;
    return 0;
}

工厂方法模式保留了简单工厂模式的优点:对接口的调用者来说,获取对象依然很简单(只需要记住参数->只需要记住具体的工厂子类),也无需修改自己的代码。同时,它克服了简单工程模式最大的缺点,增加新类或替换类无需修改客户端代码,只需要增加对应的工厂子类即可,符合开闭原则。核心的父类只定义接口,职责分散。系统拥有了良好的可扩展性。

工厂方法模式并不是完美的,在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。

在以下情况下可以使用工厂方法模式:

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