一文搞懂设计模式--工厂方法模式

4. 工厂方法(Factory Method)模式

Hi,大家好呀。昨天发的文章迟迟没有通过审核,今天一天都在和审核组斗智斗勇,问题是违规的内容在文章中压根就没有(QAQ)。唉,虽然经历了不少挫折但是生活还要继续对吧o(╥﹏╥)o。今天的主题是工厂方法模式,还是老样子,让我们先构建一个应用场景:

场景定义

今天一位尊敬的甲方来到你的公司,准备请你们帮助定制开发一个软件。产品经理几乎快说断了三寸不烂之舌,甲方代表终于满意的点点头,大手一挥在合同上写下大名。陪着甲方走出公司的大门后,产品经理终于有机会连灌了一瓶水下肚,紧接着就开始了对你的摧残。甲方的要求是这样:

今天的甲方是一个实业家,手下掌握有大量的工厂,生产众多不同的产品。但是随着工厂规模的扩大,生产过程中的环节为管理产品带来了许多问题,他希望你们能够开发一个软件帮助他管理产品生产的过程。你们经过详细的调研,了解到一个产品在工厂中通常会经历以下三个阶段

  1. 为产品选择合适的模具

  2. 采用不同的工艺生产产品

  3. 对产品进行质量检测

  4. 试用产品

其工厂的代表产品是小葱手机和尖叫鸡,于是你们打算以此为模板率先开发一个demo。

产品经理将这项艰巨的工作交给了你,本着能摸鱼绝对不划水的态度,你从手下的一众小弟中挑出一个浓眉大眼,看起来温顺无害的小伙子。对他进行了一套画饼充饥的连招后,成功让他斗志满满的决定晚上加班搞定这个需求,你满意的点点头,看看墙上的钟,估摸着到点了,晚上女神还等着你去帮他拎包呢,于是迈着六亲不认的步伐麻溜的润了。

第二天来到公司,小伙子盯着黑眼圈站在你的办公桌前,一脸兴奋告诉你他已经完成了这个需求,正等着你毫无保留的夸奖。你坐在椅子上看着小伙提交上来的代码,感觉脑仁一阵突突的疼,不断告诉自己要冷静,谁还没有年轻过,年轻人都会犯错。

简单的实现

小伙提交上来的代码是这样的

大葱手机工厂

public class PhoneFactory {
    public void selectMold(){
        System.out.println("选择大葱手机模具");
    }
    public void produce(){
        System.out.println("生产大葱手机");
    }
    public void checkout(){
        System.out.println("使用大葱手机拍核桃,检查质量是否合格");
    }
}

大葱手机

public class Phone {
    public void  use(){
        System.out.println("欢迎使用大葱手机");
    }
}

尖叫鸡工厂

public class ScreamingChickenFactory {
    public void selectMold(){
        System.out.println("选择尖叫鸡橡胶模具");
    }
    public void produce(){
        System.out.println("生产尖叫鸡");
    }
    public void checkout(){
        System.out.println("使劲捏捏尖叫鸡,看看会不会尖叫");
    }
}

尖叫鸡

public class ScreamingChicken {
    public void use(){
        System.out.println("啊啊啊啊啊啊~");
    }
}

以及调用他们的主类

public class Main {
    public static void main(String[] args) {
        // 大葱手机工厂
        PhoneFactory phoneFactory = new PhoneFactory();
        Phone phone = phoneFactory.create();
        phone.use();

        System.out.println("********************************");

        //尖叫鸡工厂
        ScreamingChickenFactory screamingChickenFactory = new ScreamingChickenFactory();
        ScreamingChicken screamingChicken = screamingChickenFactory.create();
        screamingChicken.use();
    }
}

程序输出:

选择大葱手机模具

生产大葱手机

使用大葱手机拍核桃,检查质量是否合格

欢迎使用大葱手机

********************************

选择尖叫鸡橡胶模具

生产尖叫鸡

使劲捏捏尖叫鸡,看看会不会尖叫

啊啊啊啊啊啊~

大家不要太过在意业务的合理性,构建一个背景的目的只是为了可以让我们更好的理解知识,而不是被业务的细节所迷惑

你伸手揉了揉太阳穴问道,我们这只是用这两个产品做个demo,那客户那些其他产品的工厂怎么办?

小伙子一脸无辜的说:那我在加班加点都写上去就好啦。

你感觉你的血压蹭的往上涨了一截,年轻人能熬,你codereview可熬不住。沉默了一会,你长长叹了一口气,决定将你的独门绝技传授一部分给这个年轻的小伙子。

什么是工厂方法模式

在模板方法模式中,我们在父类中规定处理的流程,在子类中实现具体的处理(什么?不知道什么是模板方法模式,快来这篇文章看看)。如果我们将该模式用于生成实例,它就演变为工厂方法模式。在工厂方法模式中,由父类决定实例的生成方式,但并不决定具体要生成的类。通过将具体的生成处理交给子类负责,这样就可以将生成实例的框架和负责生成实例的类解耦。

让我们看看用工厂方法模式如何实现上面的需求

工厂方法模式的具体实现

抽象工厂的实现

public abstract class Factory {
    /**
     * 抽象的选择模具过程
     */
    public abstract void selectMold();

    /**
     * 抽象的生产过程
     * @return 产品
     */
    public abstract Product produce();

    /**
     * 抽象的测试过程
     */
    public abstract void checkout();

    /**
     * 定义规定好的生产流程
     * @return 产品
     */
    public Product create(){
        this.selectMold();
        Product product = this.produce();
        this.checkout();
        return product;
    }
}

大葱手机工厂的实现

public class PhoneFactory extends Factory{
    /**
     * 实现具体的选择模具动作
     */
    public void selectMold(){
        System.out.println("选择大葱手机模具");
    }

    /**
     * 实现具体的生产产品动作
     * @return 大葱手机
     */
    public Product produce(){
        System.out.println("生产大葱手机");
        return new Phone();
    }

    /**
     * 实现具体的质量检测动作
     */
    public void checkout(){
        System.out.println("使用大葱手机拍核桃,检查质量是否合格");
    }
}

尖叫鸡工厂的实现

public class ScreamingChickenFactory extends Factory{
    /**
     * 具体的选择模具动作
     */
    public void selectMold(){
        System.out.println("选择尖叫鸡橡胶模具");
    }

    /**
     * 具体的生产尖叫鸡
     * @return 尖叫鸡
     */
    public Product produce(){
        System.out.println("生产尖叫鸡");
        return new ScreamingChicken();
    }
    /**
     * 具体的质量检测动作
     */
    public void checkout(){
        System.out.println("使劲捏捏尖叫鸡,看看会不会尖叫");
    }
}

抽象产品的实现

public abstract class Product {
    /**
     * 抽象的使用产品动作
     */
    public abstract void use();
}

大葱手机的实现

public class Phone extends Product{
    /**
     * 具体的使用手机
     */
    public void  use(){
        System.out.println("欢迎使用大葱手机");
    }
}

尖叫鸡的实现

public class ScreamingChicken extends Product {
    /**
     * 具体的使用尖叫鸡
     */
    public void use(){
        System.out.println("啊啊啊啊啊啊~");
    }
}

调用他们的主类

public class Main {
    public static void main(String[] args) {
        // 大葱手机工厂
        Factory factory = new PhoneFactory();
        Product product = factory.create();
        product.use();

        System.out.println("********************************");

        //尖叫鸡工厂
        // 只需要在这里进行修改就可以改变产品
        factory = new ScreamingChickenFactory();
        product = factory.create();
        product.use();
    }
}

程序运行结果:

选择大葱手机模具

生产大葱手机

使用大葱手机拍核桃,检查质量是否合格

欢迎使用大葱手机

********************************

选择尖叫鸡橡胶模具

生产尖叫鸡

使劲捏捏尖叫鸡,看看会不会尖叫

啊啊啊啊啊啊~

通过对比,很容易可以得出,通过工厂方法模式,接下来如果还有其他的产品需要加入,我们只需要通过对类进行简单的拓展,就可以适配新的产品。

工厂方法模式中出现的角色

让我么从整体上来看看工厂方法模式的类图

一文搞懂设计模式--工厂方法模式_第1张图片

Creator(创建者)

创建者属于框架的一方,他负责创建Product这个抽象类,但是具体的处理由其子类来决定。在上文的例子中Factory担任创建者角色。创建者角色并不知道要生成哪种实例,只需要调用生成实例的方法就可以生成Product实例。

Product(产品)

产品角色同样属于框架的一方,是一个抽象类。在这个角色中只定义了产品需要实现的接口,而具体的处理则交给其子类。

ConcreteCreator(具体的创建者)

ConcreteProduct角色属于具体的加工方,他实现了父类Creator中的方法,决定了具体生产的产品。上文的例子中PhoneFactory和ScreamingChickenFactory都扮演了这个角色。

ConcreteProduct(具体的产品)

ConcreteProduct属于具体的加工方,他负责生成具体的产品。上文的例子中Phone和ScreamingChicken都扮演了这个角色。

拓展思路

通过上面的例子,如果大家对模板模式有所了解的话,应该可以看出工厂模式实际上与模板模式极其类似,都是通过父类定义标准和固定的处理流程,而具体的实现方法则交给子类实现,这样的模式可以极大的增加代码的灵活度和拓展性,希望大家能够掌握其中的精髓。

当然,这两个模式也有自己的缺点,其中之一就是如果开发者没有理解在类中定义的固定流程(通常在实际开发中,业务逻辑会比上文例子中复杂数十倍),这就会导致开发者在开发其具体子类时遇到极大困难。因此我们在使用这些模式时,一定要向维护这些类的开发者准确传达这些设计模式的目的。否则将会适得其反。

往期文章

一文搞懂设计模式–外传

一文搞懂设计模式–迭代器模式

一文搞懂设计模式–适配器模式

一文搞懂设计模式–模板模式

你可能感兴趣的:(设计模式,java,设计模式,后端)