• 设计模式-工厂方法模式


    20191030175212.jpg

    概念

    工厂方法模式(Factory Method Pattern)又称工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
    工厂方法,可以理解为一种将实例化逻辑委托给子类的方法,父基类提供共有实现,派生类完成个性化定制实现

    使用时机

    如果有这样的场景,存在部分共有的功能逻辑,但是在运行时又需要动态决定使用哪个子类的逻辑实现,也就是说
    需要动态根据需求选择不同的子类实现,这个时候可以使用工厂方法。
    建议在以下情况下选用工厂方法模式。

    • 如果一个类需要创建某个接口的对象,但是又不知道具体的实现,这种情况可以选用工厂方法模式,把创建对象的工作延迟到子类中去实现。
    • 如果一个类本身就希望由他的子类来创建所需的对象的时候,应该使用工厂方法模式。

    与简单工厂的区别

    初接触工厂方法模式,会感觉,“这不是跟简单工厂一样吗”

    从本质上讲,他们确实是非常类似的,在具体实现上都是“选择实现”。但是也存在不同点,简单工厂是直接在工厂类里进行“选择实现”;而工厂方法会把这个工作延迟到子类来实现,工厂类里面使用工厂方法的地方是依赖于抽象而不是具体的实现,从而使得系统更加灵活,具有更好的可维护性和可扩展性。

    从某个角度讲,可以认为简单工厂就是工厂方法模式的一种特例,因此他们的本质是类似的。

    具体的举例,简单工厂实例中,客户就是要一个门,而不关心创建过程,最后实际创造的是一个木门,这个比较尴尬,如果客户要的是个铁门呢?所以在这个例子中,也是存在两维抽象的,一是“门”这个类型的抽象,二是“造门”这个方法的抽象。简单工厂只做到了前者,而没有给出后者的解决方案,如果看我们按照工厂方法的思路,将门工厂造门这件事进行细分,木门交给木门工厂,铁门交给铁门工厂,这就是工厂方法的实现,客户需要先制定委托对象,而不必关系具体怎么造门。

    具体实现

    C++实现

    结构图

    uml1.png

    代码实现

    #include <iostream>
    
     class IInterviewer
     {
         public:
             virtual void askQuestions() = 0;
     };
    
     class Developer : public IInterviewer
     {
         public:
             void askQuestions() override {
                 std::cout << "Asking about design patterns!" << std::endl;
             }
     };
    
     class CommunityExecutive : public IInterviewer
     {
         public:
             void askQuestions() override {
                 std::cout << "Asking about community building!" << std::endl;
             }
     };
    
     class HiringManager
     {
         public:
             void takeInterview() {
                 IInterviewer* interviewer = this->makeInterviewer();
                 interviewer->askQuestions();
             }
    
         protected:
             virtual IInterviewer* makeInterviewer() = 0;
     };
    
     template <typename Interviewer>
     class OtherManager : public HiringManager {
         protected:
             IInterviewer* makeInterviewer() override {
                 return new Interviewer();
             }
     };
    
     int main()
     {
         HiringManager* devManager = new OtherManager<Developer>();
         devManager->takeInterview();
    
         HiringManager* marketingMnager = new OtherManager<CommunityExecutive>();
         marketingMnager->takeInterview();
         return 0;
     }
    

    运行结果

    g++ -o factory-method factory-method.cpp --std=c++11
    ./factory-method
    Asking about design patterns!
    Asking about community building!
    

    总结

    IInterviwer为基础类,定义为一个虚基类,具体派生出了Devoloper和CommunityExecutive两个实现子类;
    HiringManager为工厂基类,定义为一个虚基类,OtherManager为具体实现的派生类,根据传入的template type,返回不同的创建对象。

    Golang实现

    结构图

    factory-method.png

    代码实现

    package factory_method
    
    
    //Operator是被封装的接口
    type Operator interface {
    	SetA(int)
    	SetB(int)
    	Result() int
    }
    
    //工厂接口
    type OperatorFactory interface {
    	Create() Operator
    }
    
    //OperatorBase是Operator接口实现的基类,封装公有方法
    type OperatorBase struct {
    	a,b int
    }
    
    //SetA方法实现
    func (op *OperatorBase) SetA(aValue int) {
    	op.a = aValue
    }
    
    //SetB方法实现
    func (op *OperatorBase) SetB(bValue int) {
    	op.b = bValue
    }
    
    //下面是分别构造不同类型Operator以及对应生产的工厂类
    
    //加法工厂类
    type PlusOperatorFactory struct {
    
    }
    
    //加法工厂类实现工厂接口
    func (pof PlusOperatorFactory) Create() Operator {
    	return &PlusOperator{}
    }
    
    //加法类
    type PlusOperator struct {
    	OperatorBase
    }
    
    //加法类实现Operator接口的Result函数
    func (pop *PlusOperator) Result() int {
    	return pop.a + pop.b
    }
    
    //减法工厂类
    type MinusOperatorFactory struct {
    
    }
    
    //减法工厂类实现工厂接口
    func (mof MinusOperatorFactory) Create() Operator {
    	return &MinusOperator{}
    }
    
    //减法类
    type MinusOperator struct {
    	OperatorBase
    }
    
    //减法类实现Operator接口的Result函数
    func (mop *MinusOperator) Result() int {
    	return mop.a - mop.b
    }
    

    测试用例

    package factory_method
    
    import "testing"
    
    func TestPlusOperator_Result(t *testing.T) {
    	 pof := PlusOperatorFactory{}
    	 pop := pof.Create()
    	 pop.SetA(1)
    	 pop.SetB(2)
    	 if pop.Result() != 3 {
    	 	t.Fatal("test plus operator factory failed")
    	 }
    }
    
    func TestMinusOperator_Result(t *testing.T) {
    	mof := MinusOperatorFactory{}
    	mop := mof.Create()
    	mop.SetA(2)
    	mop.SetB(1)
    	if mop.Result() != 1 {
    		t.Fatal("test minus operator factory failed")
    	}
    }
    

    运行结果

    go test -v factory-method.go factory-method_test.go
    === RUN   TestPlusOperator_Result
    --- PASS: TestPlusOperator_Result (0.00s)
    === RUN   TestMinusOperator_Result
    --- PASS: TestMinusOperator_Result (0.00s)
    PASS
    ok      command-line-arguments  0.734s
    

    优化后更实用的版本

    func LoadFactory(name string) OperatorFactory {
    	switch name {
    	case "plus":
    		return PlusOperatorFactory{}
    	case "minus":
    		return MinusOperatorFactory{}
    	default:
    		return PlusOperatorFactory{}
    	}
    }
    

    测试用例

    ......
    pof := LoadFactory("plus")
    ......
    

    工厂方法模式的思考

    工厂方法模式的缺点

    • 在添加新产品时,需要编写新的具体产品类,而且还需要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销
    • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度。
  • 相关阅读:
    poj 1191(棋盘分割)
    poj 1184(聪明的打字员)
    HDU 3593(The most powerful force)
    poj 2449(Remmarguts' Date)
    poj 1837(blance)
    poj 1742(Coins)
    poj 3280(Cheapest Palindrome)
    poj 1077(八数码)
    数组排序1.和求最大值
    当textindent与float相遇
  • 原文地址:https://www.cnblogs.com/jingliming/p/11766802.html
Copyright © 2020-2023  润新知