设计模式:工厂模式(简单工厂/工厂方法/抽象工厂全面对比理解)

目录

 

一、 简单介绍

二、简单工厂

2.1 新需求,要求根据简单工厂设计

2.2 简单工厂流程图

2.3 简单工厂实例代码

2.4 简单工厂总结

三、工厂方法模式

3.1 工厂方法包括4个角色

3.2 工厂方法实例结构图

3.3 工厂方法实例代码

3.4 工厂方法实例代码分析

3.5 工厂方法总结

四、抽象工厂

4.1 抽象工厂包括4个角色

4.2 抽象工厂实例结构图

4.2 抽象工厂实例代码

4.4 抽象工厂实例代码分析


一、 简单介绍

实际上我们可能常用的工厂模式只是简单工厂(静态方法工厂),严格说来这可能只是一种编程优化的习惯,不能说程为是一种设计模式,但是不管是简单工厂工厂方法还是抽象工厂都是为软件架构服务的,具体选择哪一种需要仔细考量,绝对不能为用而用,不要装逼装高深,简单、易用、易于理解和维护才是目的。这篇文章对工厂模式进行一个大概的介绍,便于理解记忆

上图中的工厂方法和抽象工厂都包含了相同的角色,但是在具体的架构中是有所不同的。

 

 

二、简单工厂

简单工厂,也叫作静态方法工厂,包含了三个角色工厂类、抽象产品,具体产品,所有的产品都在工厂类类里面统一初始化,并通过工厂类的静态方法统一输出。

通过一个需求来切入。

2.1 新需求,要求根据简单工厂设计

BMW公司需要造车,包括320和520两款车型,除了汽车引擎外,其它零件都是自己生产,Engine的生产(很复杂)可以自己生产或者外包,整车从制造到交付客户的流程设计?

 

2.2 简单工厂流程图

 

 

2.3 简单工厂实例代码

public interface IBmwEngine {

    void fire();
    void run();
    void stop();
}




public class Bmw320Engine implements IBmwEngine{
    @Override
    public void fire() {
        System.out.println("BMW320, fire!over!");
    }

    @Override
    public void run() {
        System.out.println("BMW320, run!over!");
    }

    @Override
    public void stop() {
        System.out.println("BMW320, stop!over!");
    }
}




public class Bmw520Engine implements IBmwEngine {
    @Override
    public void fire() {
        System.out.println("BMW520, fire!over!");
    }

    @Override
    public void run() {
        System.out.println("BMW520, run!over!");
    }

    @Override
    public void stop() {
        System.out.println("BMW520, stop!over!");
    }
}



public class BmwEngineFactory {
    public final static int BMW_320 = 320;
    public final static int BMW_520 = 520;

    public static IBmwEngine createEngine(int type) {
        IBmwEngine engine = null;
        switch (type) {
            case BMW_320:
                engine = new Bmw320Engine();
                break;
            case BMW_520:
                engine = new Bmw520Engine();
                break;
        }
        return engine;
    }
}



public class BmwMaker {

    /**
     * 准备Engine
     */
    private IBmwEngine prepareEngine(int typeEngine) {
       return BmwEngineFactory.createEngine(typeEngine);
    }

    public static void main(String[] args) {
        BmwMaker maker  = new BmwMaker();
        IBmwEngine engine = maker.prepareEngine(BmwEngineFactory.BMW_320);
        engine.fire();
        engine.run();
        engine.stop();
    }
}


测试结果:
BMW320, fire!over!
BMW320, run!over!
BMW320, stop!over!

 

2.4 简单工厂总结

上面代码是一个很简单的例子,也十分方便运用到实际工作中,汽车需要发动机,不同型号的发动机作为被需要的对象,分为不同的种类,统一通过工厂类创建实例和管理,上面写的比较简单,实例的创建过程涉及到诸多方面,这些细节不对外暴露,试想一下如果我们直接在BmwMaker类中new出我们的对象,然后处理各种细节,那么我们在BmwMaker需要很多逻辑来管理不同实例,这是比较复杂的,但是如果通过工厂统一处理,那么BmwMaker只需要拿来用就行了,我不需要操心实例创建的细节。

由此可以总结出简单工厂的一些特点:

优点:简单工厂根据外界给定的信息选择创建哪个具体类的对象,明确区分了各自的职责和权力,有利于整个软件体系结构的优化。

 

上面只是320 和520 两个类型的,如果我们需要增加更多的类型的话,我们需要增加不同的Engine类型来实现IBmwEngine接口,然后在BmwEngineFactory工厂类中添加分支输出新类型,显然我们需要修改之前已经存在的BmwEngineFactory类,违反了软件设计的封闭原则,当然这里我们举例比较简单,修改起来也不费事,当然如果我们确实在开发中也是这样的情况,那么我们这样做也没有什么问题,以最简单的方式解决问题效率会更高。但是如果遇到交付的代码不允许修改,那么我们就需要考虑新的架构了。

缺点:

每增加一个新的类别都会在工厂类中的进行添加,也违背了软件设计的封闭原则;

工厂类集中了所有实例创建的逻辑,违反了高内聚的责任分配原则。

 

三、工厂方法模式

针对简单工厂的缺点,进一步对架构升级,引出工厂方法模式

 

3.1 工厂方法包括4个角色

1、抽象产品: Product

2、具体产品:ConcreteProduct

3、抽象工厂:Factory

4、具体工厂:ConcreateFactory

dcb4bc0db65c9af350133eb142d11cee3eb.jpg

 

3.2 工厂方法实例结构图

 

3.3 工厂方法实例代码
 


public interface BmwEngineFactory {
    public final static int BMW_320 = 320;
    public final static int BMW_520 = 520;

    IBmwEngine createEngine();
}




public class Bmw320EngineFactory implements BmwEngineFactory{

    @Override
    public Bmw320Engine createEngine() {
        return new Bmw320Engine();
    }
}




public class Bmw520EngineFactory implements BmwEngineFactory{

    @Override
    public Bmw520Engine createEngine() {
        return new Bmw520Engine();
    }
}




public interface IBmwEngine {

    void fire();
    void run();
    void stop();
}



public class Bmw320Engine implements IBmwEngine {
    @Override
    public void fire() {
        System.out.println("BMW320, fire!over!");
    }

    @Override
    public void run() {
        System.out.println("BMW320, run!over!");
    }

    @Override
    public void stop() {
        System.out.println("BMW320, stop!over!");
    }
}



public class Bmw520Engine implements IBmwEngine {
    @Override
    public void fire() {
        System.out.println("BMW520, fire!over!");
    }

    @Override
    public void run() {
        System.out.println("BMW520, run!over!");
    }

    @Override
    public void stop() {
        System.out.println("BMW520, stop!over!");
    }
}




public class BmwMaker {

    public static void main(String[] args) {
        BmwMaker maker  = new BmwMaker();
        IBmwEngine engine = maker.prepareEngine320();
        engine.fire();
        engine.run();
        engine.stop();
    }


    private IBmwEngine prepareEngine320() {
        Bmw320EngineFactory bmwEngineFactory = new Bmw320EngineFactory();
        return bmwEngineFactory.createEngine();
    }

}

 

3.4 工厂方法实例代码分析

上面的实例代码包括:

抽象工厂类:BmwEngineFactory

实例工厂类:Bmw320EngineFactory、Bmw520EngineFactory,它们两个实现了抽象工厂BmwEngineFactory

抽象产品类:IBmwEngine

具体产品类:Bmw320Engine、Bmw520Engine,它们两个实现了抽产品IBmwEngine

测试类:BmwMaker

看起来我们的代码结构复杂了,似乎我们并不需要工厂,这是从代码量的角度来考虑问题,过于狭隘。换个角度,通过不同的工厂管控对应的不同类型的实例化过程,细节完全对外屏蔽,只是提供实例对象获取接口,从这个层面上让使用和创建分开,便于分层,便于对象创建的逻辑管理。将工厂抽象成接口,提升层级,具体的工厂分别实现,有助于扩展,并且完全符合软件设计的开放封闭原则。

 

3.5 工厂方法总结

工厂方法虽然在一定程度上对简单工厂的短板进行了弥补,但是由于具体工厂和抽象工厂的分层,让代码量也成倍增长了。上面只是单维度的发动机制造,如果我们进一步加入,车架(Frame)、轮胎(Tire)等种类的对象,继续使用工厂方法来设计架构,我们将遇到比较麻烦的问题,比如为了确保320系列的Engine、Frame和Tire的组合的正确性你需要在使用到的地方维护彼此的逻辑,不能让520系列的零件和320的组合,那么我们在增加730系列呢?整个逻辑的管控将会变的无比庞大和复杂,而实际上我们只想简单的使用,需要制造320系列的车型的时候,我希望有一个工厂将整套零件一起返回,我不需要管理复杂的搭配。

 

如下如,增加Frame后,继续使用工厂方法模式的架构如下,在BmwMaker类中需要添加维护320系列和520系列组件的逻辑,以确保不会被混搭。

 

 

 

 

四、抽象工厂

在组成角色中抽象工厂和工厂方法并没有什么不同,不同的只是两个架构的设计,在系统的复杂度增加,产品的维度增加的时候,为了流程的清晰和逻辑的维护简单,需要从产品维度上调整,比如,我们不再使用产品种类这个维度来划分工厂,而是以一个系列来划分,比如320系列的产品,统一通过Bmw320Factory来输出,其中包含createEngine、createFrame等方法,统一返回同一型号的组件,这样避免了组装车间混淆不同型号的组件。

 

4.1 抽象工厂包括4个角色

1、抽象产品: Product

2、具体产品:ConcreteProduct

3、抽象工厂:Factory

4、具体工厂:ConcreateFactory

dcb4bc0db65c9af350133eb142d11cee3eb.jpg

 

 

4.2 抽象工厂实例结构图

 

4.2 抽象工厂实例代码

 

代码机构如下如,对照看:

 


public interface IBmwEngine {

    void fire();
    void run();
    void stop();
}


public class Bmw320Engine implements IBmwEngine {
    @Override
    public void fire() {
        System.out.println("BMW320, fire!over!");
    }

    @Override
    public void run() {
        System.out.println("BMW320, run!over!");
    }

    @Override
    public void stop() {
        System.out.println("BMW320, stop!over!");
    }
}


public class Bmw520Engine implements IBmwEngine {
    @Override
    public void fire() {
        System.out.println("BMW520, fire!over!");
    }

    @Override
    public void run() {
        System.out.println("BMW520, run!over!");
    }

    @Override
    public void stop() {
        System.out.println("BMW520, stop!over!");
    }
}





public interface IBmwFrame {

    void install();
}


public class Bmw320Frame implements IBmwFrame {

    @Override
    public void install() {
        System.out.println("BMW320 Frame, install!over!");
    }
}




public class Bmw520Frame implements IBmwFrame {

    @Override
    public void install() {
        System.out.println("BMW520 Frame, install!over!");
    }
}



public interface BmwFactory {
    IBmwEngine createEngine();
    IBmwFrame createFrame();
}



public class Bmw320Factory implements BmwFactory {

    @Override
    public IBmwEngine createEngine() {
        return new Bmw320Engine();
    }

    @Override
    public IBmwFrame createFrame() {
        return new Bmw320Frame();
    }
}



public class Bmw520Factory implements BmwFactory {

    @Override
    public IBmwEngine createEngine() {
        return new Bmw520Engine();
    }

    @Override
    public IBmwFrame createFrame() {
        return new Bmw520Frame();
    }
}




public class BmwMaker {

    public static void main(String[] args) {
        BmwMaker maker  = new BmwMaker();
        maker.prepareParts320();
    }


    private void prepareParts320() {
        Bmw320Factory bmw320Factory = new Bmw320Factory();
        IBmwEngine engine = bmw320Factory.createEngine();
        engine.fire();
        engine.run();
        engine.stop();
        IBmwFrame frame = bmw320Factory.createFrame();
        frame.install();
    }

}

 

4.4 抽象工厂实例代码分析

上面的逻辑分层相对于工厂方法模式进行了改变,可以用下面的图来区别,工厂方法以纵向划分成不同零件的工厂,抽象工厂以横向车型系列进行划分一次性返回同一型号的各种零件,从而避免了系列之间的逻辑控制的混乱。

 

图4-1:工厂方法的产品的划分,以产品种类划分,建立工厂

 

图4-2:抽象工厂的产品的划分,以产品系列划分,建立工厂

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章