Factory Pattern

2020-03-11  本文已影响0人  路过的魔法师

介绍工厂方法模式之前,先说两句设计模式是什么。

设计模式公认的开山之作是这本:

GoF
设计模式:可复用面向对象软件的基础,关键字是复用和面向对象,复用是目的,面向对象是手法

提一句,这里的复用并不是ctrl-c过来,ctrl-v过去的源码级复用,设计模式追求的是编译单元也就是二进制级别的复用。
复用,那为什么要复用呢?因为变化啊,客户需求的变化、开发团队的变化、技术平台的变化、市场环境的变化等等,你说我写代码就是为了算1+1的,还需要考虑这些干嘛,甚至都不需要计算,直接返回2就解决了,可实际上我还真没写过仅仅只是计算1+1的代码。
前面说复用是目的,面向对象是手法,为什么面向对象较传统的面对过程而言可以在一定程度上抵御变化呢?
如何通俗易懂地举例说明「面向对象」和「面向过程」有什么区别?,请。

设计模式的概念通常使用Christopher Alexander的说法:

Each pattern describes a problem that occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice.

差不多就是类似常规题的通用解法的意思。这里省去了自己总结的步骤,有些问题没有重复地亲自遇见过,平时写project就是千行级别的,没有团队,也没有甲方爸爸,直接就看手法,有点像小学还在背着乘法口诀表,被塞一本《口算心算秘籍》之流一般,我那会儿就是满口的“善善善”,十多年过去了也就记住了(a5)^{2}=a(a+1) * 100 +25。现在想想,这所谓的“秘籍”说穿了就是根据加减乘除运算法则推导出来的,我也可以写书卖钱了啊。说了这么多题外话的意思是初看设计模式不理解问题不很大,不用刻意地去模仿,总会理解的,到一定水平也可以总结出属于自己的设计模式。

当然像“四则运算法则”这样的东西是要记住的,面向对象对应的通常来说是“SOLID principles”,SOLID是以下五个principle的首字母:

直译过来分别就是单一职责原则、开放封闭原则、里氏替换原则、接口隔离原则、依赖倒置原则,具体指什么,翻译过来就缺了点味道,有兴趣的可以点链接看看。

Simple Factory Pattern

看过设计模式的可能会疑惑,GoF里没提到simple factory啊,是没提到,可前面说了design pattern就是历代程序员们总结出来的一套设计模板,实际中simple factory使用频率是很高的,GoF没收录罢了。随便写一段给你瞧瞧:

#include <iostream>
using namespace std;

class IPhone {
public:
    IPhone() = default;
    virtual ~IPhone() = default;
    virtual void ring() = 0;
};

class NokiaPhone : public IPhone {
public:
    NokiaPhone() = default;
    ~NokiaPhone() = default;

    void ring() {
        cout << "Nokia is ringing..." << endl;
    }
};

class SonyPhone : public IPhone {
public:
    SonyPhone() = default;
    ~SonyPhone() = default;

    void ring() {
        cout << "Sony is ringing..." << endl;
    }
};

int main(void) {

    IPhone* phone;
    string brand;
    cin >> brand;
    if (brand == "Nokia") {
        phone = new NokiaPhone();
    } else if (brand == "Sony") {
        phone = new SonyPhone();
    }

    phone->ring();

    return 0;
}

啊,贴错了,请看下面的:

#include <iostream>
using namespace std;

class IPhone {
public:
    IPhone() = default;
    virtual ~IPhone() = default;
    virtual void ring() = 0;
};

class NokiaPhone : public IPhone {
public:
    NokiaPhone() = default;
    ~NokiaPhone() = default;

    void ring() {
        cout << "Nokia is ringing..." << endl;
    }
};

class SonyPhone : public IPhone {
public:
    SonyPhone() = default;
    ~SonyPhone() = default;

    void ring() {
        cout << "Sony is ringing..." << endl;
    }
};

// add
class SimpleFactory {
public:
    static IPhone* create(string brand) {
        if (brand == "Nokia") {
            return new NokiaPhone();
        } else if (brand == "SonyPhone") {
            return new SonyPhone();
        }
    }
};

int main(void) {

    string brand;
    cin >> brand;

    // modify
    IPhone* nokia = SimpleFactory::create(brand);
    nokia->ring();

    return 0;
}

相比第一段代码多了一个具体类,实例化对象的职责交给了它去处理。这有什么好处呢?
首先,说一下第一段代码的问题,类的使用者,没必要知道类的具体细节,不然就有点违反封装的概念,并且也违反了单一职责原则,既然如此那我就把这部分代码拿出来封装一下好了。
闲扯一句,你细品添加一个SimpleFactory类有没有中间层的思想在里面,遇到问题(假设此处有)不妨先加个中间层,解决不了再加一层,这不是没有道理的。
这就是Simple Factory Pattern。

Factory Method Pattern

Simple Factory能解决普遍问题了吗?来,甲方爸爸说给我整一个SamsungPhone出来。
修改SimpleFactory类?这不又违反了开放封闭原则了吗。
怎么解决呢,Simple Factory抽象出来一个专门用来实例化对象的类,再抽象一层呢?

#include <iostream>
using namespace std;

class IPhone {
public:
    IPhone() = default;
    virtual ~IPhone() = default;
    virtual void ring() = 0;
};

class NokiaPhone : public IPhone {
public:
    NokiaPhone() = default;
    ~NokiaPhone() = default;

    void ring() {
        cout << "Nokia is ringing..." << endl;
    }
};

class SonyPhone : public IPhone {
public:
    SonyPhone() = default;
    ~SonyPhone() = default;

    void ring() {
        cout << "Sony is ringing..." << endl;
    }
};

class SamsungPhone : public IPhone {
public:
    SamsungPhone() = default;
    ~SamsungPhone() = default;

    void ring() {
        cout << "Samsung is ringing..." << endl;
    }
};

// add
class IFactory {
public:
    virtual IPhone* create() = 0;
};

class NokiaFactory : public IFactory {
public:
    IPhone* create() {
        return new NokiaPhone();
    }
};

class SonyFactory : public IFactory {
public:
    IPhone* create() {
        return new SonyPhone();
    }
};

class SamsungFactory : public IFactory {
public:
    IPhone* create() {
        return new SamsungPhone();
    }
};

int main(void) {

    // modify
    IFactory* factory = new NokiaFactory();
    IPhone* phone = factory->create();
    
    phone->ring();

    return 0;
}

这就是Factory Method Pattern的标准框架

现在来看Factory Method Pattern的定义就清晰多了:

A Factory Pattern or Factory Method Pattern says that just define an interface or abstract class for creating an object but let the subclasses decide which class to instantiate.In other words, subclasses are responsible to create the instance of the class.
The Factory Method Pattern is also known as Virtual Constructor.

Abstract Factory Pattern

Abstract Factory Pattern says that just define an interface or abstract class for creating families of related (or dependent) objects but without specifying their concrete sub-classes.That means Abstract Factory lets a class returns a factory of classes. So, this is the reason that Abstract Factory Pattern is one level higher than the Factory Pattern.
An Abstract Factory Pattern is also known as Kit.

Abstract Factory Patterny又是干嘛的呢?还是刚刚的例子,如果再添加充电器呢,目前为了达到快充的目的,充电器需要与手机快充协议相匹配。塞到一个类里?直觉说不能这么干,不容易维护不说,我只想要一个SonyPhone怎么办。像解决Phone那样使用Factory Method Pattern并让使用者自己决定怎么搞去?显然也不行。
那...把Factory塞到一起?好像可以哎。

#include <iostream>
using namespace std;

class IPhone {
public:
    IPhone() = default;
    virtual ~IPhone() = default;
    virtual void ring() = 0;
};

class NokiaPhone : public IPhone {
public:
    NokiaPhone() = default;
    ~NokiaPhone() = default;

    void ring() {
        cout << "Nokia is ringing..." << endl;
    }
};

class SonyPhone : public IPhone {
public:
    SonyPhone() = default;
    ~SonyPhone() = default;

    void ring() {
        cout << "Sony is ringing..." << endl;
    }
};

class SamsungPhone : public IPhone {
public:
    SamsungPhone() = default;
    ~SamsungPhone() = default;

    void ring() {
        cout << "Samsung is ringing..." << endl;
    }
};

// add
class ICharger {
public:
    ICharger() = default;
    virtual ~ICharger() = default;

    virtual void charge() = 0;
};

class NokiaCharger : public ICharger {
public:
    NokiaCharger() = default;
    ~NokiaCharger() = default;

    void charge() {
        cout << "NokiaPhone and NokiaCharger." << endl;
    }
};

class SonyCharger : public ICharger {
public:
    SonyCharger() = default;
    ~SonyCharger() = default;

    void charge() {
        cout << "SonyPhone and SonyCharger." << endl;
    }
};

class SamsungCharger : public ICharger {
public:
    SamsungCharger() = default;
    ~SamsungCharger() = default;

    void charge() {
        cout << "SamsungPhone and SamsungCharger." << endl;
    }
};

// modify
class IFactory {
public:
    virtual IPhone* createPhone() = 0;
    virtual ICharger* createCharger() = 0;
};

class NokiaFactory : public IFactory {
public:
    IPhone* createPhone() {
        return new NokiaPhone();
    }
    ICharger* createCharger() {
        return new NokiaCharger();
    }
};

class SonyFactory : public IFactory {
public:
    IPhone* createPhone() {
        return new SonyPhone();
    }
    ICharger* createCharger() {
        return new SonyCharger();
    }
};

class SamsungFactory : public IFactory {
public:
    IPhone* createPhone() {
        return new SamsungPhone();
    }
    ICharger* createCharger() {
        return new SamsungCharger();
    }
};

int main(void) {

    IFactory* factory = new NokiaFactory();
    IPhone* phone = factory->createPhone();
    ICharger* charger = factory->createCharger();

    phone->ring();
    charger->charge();

    return 0;
}

Summary

Simple Factory Pattern -> Factory Method Pattern -> Abstract Factory Pattern 抽象的层次越来越高。

面向接口编程、单一职责原则、开放封闭原则、里氏替换原则等等原则以及面向对象的三大特性继承、封装、多态在Factory Pattern中或多或少的得到了体现。

唔,Factory Pattern缺点也很明显,扩展子类需要派生新子类不说,还要为其写对应的工厂方法。

References
SOLID principles
Design Patterns in Java

上一篇 下一篇

猜你喜欢

热点阅读