zoukankan      html  css  js  c++  java
  • Factory Method模式精解(C++版本)


    继续之前的设计模式第四弹,这次是大名鼎鼎的工厂方法模式。

    使用情景

    定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method是创建型模式,使一个类的实例化延迟到其子类。

    Factory有工厂的意思,简单来看,这个模式利用到了上一篇的Template Method模式用来生成具体的实例,说得更清楚一点,工厂方法模式将创建对象的过程延迟到子类实现,其他的父类的步骤保持完整。

    问题引入

    想象一个养殖业的农民,他刚开始仅仅在养马场养马,每个马都需要养殖长大之后在市面出售,后来他获得足够的利润之后,扩展业务也养牛,但是在牛场养牛,每头牛也是需要养殖长大之后在市面出售的。在刚开始的时候,我们需要记录每只马的养殖过程,后面还要记录它的售价。如果你前面只有养马的程序(包括生产、饲养、销售的过程),比如下面这样

    class Farm {
    public:
        CreateHorse();
        FeedHorse();
        SellHorse();
    private:
        Horse horse_;
    }
    
    

    需要添加金养牛的程序,那么大多数情况会出现一个switch的分支,随着饲养的品种越来越多,最后会在生产、饲养和售卖的各个过程中出现多个switch分支。如果我是农场主,代码会陷入“分支瘫痪”,对维护这一套代码感到厌烦。比如下面这样

    class Farm {
    public:
        CreateAnimal() {
            if (animaltype == "horse") {
                // create horse
            } else if (animaltype == "cow") {
                // ceate cow
            } ...
            else {
                // create others
            }
        }
        FeedAnimal() {
            if (animaltype == "horse") {
                // feed horse
            } else if (animaltype == "cow") {
                // feed cow
            } ...
            else {
                // feed others
            }
        }
        SellAnimal() {
            if (animaltype == "horse") {
                // sell horse
            } else if (animaltype == "cow") {
                // sell cow
            } ...
            else {
                // sell others
            }
    
        }
    private:
        int animaltype;
    

    这样的方案有什么明显的缺点呢?

    • 高耦合,这个大类中的函数有一处需要添加分支,每个函数就都需要变化,但是每个函数实际是售卖动物的不耦合的步骤(生产不影响饲养,饲养不影响售卖),这些步骤之间耦合太紧,导致“霰弹式修改”;
    • 分支瘫痪,添加的类别越多,代码的if/else/switch的分支越多,最后陷入分支瘫痪的状态。

    解决方案

    按照《设计模式解析》中的原则,设计模式需要遵循如下的一些原则:

    1. 考虑设计中什么应该是可变的;
    2. 对变化的概念进行封装;
    3. 优先使用对象聚集而不是类继承

    在上面的例子中,有两个基本要素——农场和动物,每一个类应该对自己的职责负责

    • 农场负责生产和饲养动物,不同种类的动物生产和饲养的方式都不同;
    • 动物被售卖,不同的动物售卖的价格均不同;

    可以看出可以将之前的方案拆解成两个类FarmAnimal,而且生产、饲养和售卖的方式都是可变的,所以这些方法都是虚方法。对于具体的动物,生成具体的农场和动物。

    UML表示及其代码

    参考解决方案的内容,我们画出这些类的UML的图,如下所示

    具体的代码如下所示

    #include <iostream>
    using namespace std;
    
    class Animal {
    public:
    	virtual void Sell() = 0;
    };
    
    class Horse : public Animal {
    public:
    	Horse(int price = 5, int id = 0) : price_(price), id_(id) {};
    	void Sell() {
    		cout << id_ << ": Horse sell " << price_ << " yuan
    ";
    	}
    private:
    	int price_;
    	int id_;
    };
    
    class Cow : public Animal {
    public:
    	Cow(int price = 7, int id = 0) : price_(price), id_(id) {};
    	void Sell() {
    		cout << id_ << ": Cow sell " << price_ << " yuan
    ";
    	}
    private:
    	int price_;
    	int id_;
    };
    
    class Farm {
    public:
    	virtual Animal* Create(int id, int price) = 0;
    };
    
    class HorseFarm : public Farm {
    public:
    	Animal* Create(int id, int price)
    	{
    		return new Horse(price, id);
    	}
    };
    
    class CowFarm : public Farm {
    public:
    	Animal* Create(int id, int price)
    	{
    		return new Cow(price, id);
    	}
    };
    
    int main()
    {
    	Farm* factory = new HorseFarm();
    	Animal* horse = factory->Create(0, 32);
    	horse->Sell();
    
    	factory = new CowFarm();
    	Animal* cow = factory->Create(0, 12);
    	cow->Sell();
    
    	delete factory;
    	delete horse;
    	delete cow;
    	return 0;
    }
    
  • 相关阅读:
    linux kill命令以及 信号
    rhel7 系统服务——unit(单元)
    redis集群在线迁移
    二、主目录 Makefile 分析(3)
    二、主目录 Makefile 分析(2)
    二、主目录 Makefile 分析(1)
    一、文档目录分析
    Linux下解压缩
    设备树
    轮询
  • 原文地址:https://www.cnblogs.com/bugxch/p/14726964.html
Copyright © 2011-2022 走看看