Java设计模式——工厂模式

Posted programmerkaixin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java设计模式——工厂模式相关的知识,希望对你有一定的参考价值。

Java设计模式——工厂模式

工厂模式(Factory Pattern)属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。术业有专攻就能很好的解释工厂模式,工厂模式就是专业生产商,我们拿来用就好了,不需要自己粗制乱遭,也不需要购买假冒伪劣产品,正规渠道拿货,质量有保障,安全,放心。

简单工厂模式

简单工厂模式不属于23种设计模式。他是由一个工厂实例来创建我们所需要的实例,适用于工厂类创建对象较少的场景。客户端只需要传入合适的参数就能获取所需对象,不需要关心对象的创建逻辑。

代码示例:

/**
 * @description: 水果产品接口
 * @author: lmc
 * @create: 2019-03-19 21:28
 **/

public interface IFruits {

    /**
     * 水果名称
     */
    void getName();

    /**
     * 水果颜色
     */
    void getColor();

    /**
     * 水果味道
     */
    void getTaste();

}
/**
 * @description: 苹果
 * @author: lmc
 * @create: 2019-03-19 21:33
 **/

public class Apple implements IFruits {

    @Override
    public void getName() {

        System.out.println(" 我是苹果,水果的一种");
    }

    @Override
    public void getColor() {
        System.out.println(" 苹果是红色的");
    }

    @Override
    public void getTaste() {
        System.out.println(" 苹果馋起来很甜很脆");
    }
}
/**
 * @description: 香蕉
 * @author: lmc
 * @create: 2019-03-19 21:33
 **/

public class Banana implements IFruits {

    @Override
    public void getName() {

        System.out.println(" 我是香蕉,水果的一种");
    }

    @Override
    public void getColor() {
        System.out.println(" 香蕉是黄色的");
    }

    @Override
    public void getTaste() {
        System.out.println(" 香蕉馋起来很甜很滑");
    }
}
/**
 * @description: 橙子
 * @author: lmc
 * @create: 2019-03-19 21:33
 **/

public class Orange implements IFruits {

    @Override
    public void getName() {

        System.out.println(" 我是橙子,水果的一种");
    }

    @Override
    public void getColor() {
        System.out.println(" 橙子是橙色的");
    }

    @Override
    public void getTaste() {
        System.out.println(" 橙子馋起来很甜水分足");
    }
}

上面的代码 创建了一个水果接口,并且创建了三种水果分别实现了水果接口。

/**
 * @description: 水果工厂
 * @author: lmc
 * @create: 2019-03-19 21:38
 **/

public class FruitsFactory {

    /**
     * @description: 
     * @param fruitsName
     * @return com.lmc.gp12380.pattern.factory.fruits.IFruits
     * @date 2019/5/23 15:44
     * @author lmc
     */
    public IFruits product(String fruitsName){

        if(null != fruitsName && fruitsName != ""){
            System.out.println("客户需求的水果是"+fruitsName);
            if("苹果".equals(fruitsName)){
                System.out.println("水果工厂生产了苹果");
                return new Apple();
            }
            if("橙子".equals(fruitsName)){
                System.out.println("水果工厂生产了橙子");
                return new Orange();
            }
            if("香蕉".equals(fruitsName)){
                System.out.println("水果工厂生产了香蕉");
                return new Banana();
            }
            return null;
        }else{
            return null;
        }
    }
}

简单工厂测试类

/**
 * @description: 水果工厂测试类
 * @author: lmc
 * @create: 2019-03-19 21:50
 **/

public class SimpleFactoryTest {

    public static void main(String[] args) {
        IFruits ifruits=null;
        FruitsFactory ifruitsFactory =new FruitsFactory();

        ifruits = ifruitsFactory.product("香蕉");
        getFruitsName(ifruits,"香蕉");

        ifruits = ifruitsFactory.product("苹果");
        getFruitsName(ifruits,"苹果");

        ifruits = ifruitsFactory.product("橙子");
        getFruitsName(ifruits,"橙子");

        ifruits = ifruitsFactory.product("草莓");
        getFruitsName(ifruits,"草莓");

    }

    public static void getFruitsName(IFruits ifruits,String ifruitsName){

        if(null != ifruits){
            ifruits.getName();
        }else{
            if(null == ifruitsName || ifruitsName==""){
                System.out.println("未指定水果让水果工厂生产");
            }else{
                System.out.println("水果工厂暂时无法生产"+ifruitsName);
            }

        }
    }
}

测试结果

客户需求的水果是香蕉
水果工厂生产了香蕉
我是香蕉,水果的一种

客户需求的水果是苹果
水果工厂生产了苹果
我是苹果,水果的一种

客户需求的水果是橙子
水果工厂生产了橙子
我是橙子,水果的一种

客户需求的水果是草莓
水果工厂暂时无法生产草莓

上面的代码很简单,客户传入不同的参数,就能获取工厂对象能够生产的产品。业务需求中,工厂实例创建对象的业务逻辑往往是复杂的,运用简单工厂模式,客户端就不需要关心业务了,只要创建工厂对象,传入参数调用就能获取所需对象。

利:客户端调用简单,对于简单的业务逻辑清晰明了。

弊:

  • 需要传参,容易出错。
    • 传一个草莓参数,或者其他乱七八糟的参数,就得不到所需对象,出问题了
  • 业务需要新的对象,需要更改工厂类,违背了开闭原则。
    • 就像上面那样,我要一个草莓对象,工厂类暂时无法创建,需要修改代码。
  • 工厂类的职责过重,不利于扩展复杂的产品结构(产品族和产品等级结构的概念后面会有说到)。
    • 随着要生产的对象越来越多,工厂类变成了万能工厂了,违背了单一原则,不利于扩展和维护。

简单工厂类图:
技术图片

工厂方法

工厂方法模式(FactoryMethodPattern)是指定义一个创建对象的接口(工厂接口),但让实现这个
接口的类(工厂具体实现类)来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。

现代化管理都是明确分工、专人干专事、团队协作。咱们的程序代码意思一样的。

来一个水果工厂接口

/**
 * @description: 水果工厂接口
 * @author: lmc
 * @create: 2019-03-20 20:14
 **/

public interface IFruitsFactory {
    /**
     * 工厂的生产方法
     * @return IFruits
     */
    IFruits product();

}
/**
 * @description: 苹果工厂
 * @author: lmc
 * @create: 2019-03-20 20:19
 **/

public class AppleFactory implements IFruitsFactory {
    @Override
    public IFruits product() {

        System.out.println("苹果工厂只生产苹果");
        return new Apple();
    }
}
/**
 * @description: 香蕉工厂
 * @author: lmc
 * @create: 2019-03-20 20:19
 **/

public class BananaFactory implements IFruitsFactory {
    @Override
    public IFruits product() {
        System.out.println("香蕉工厂只生产香蕉");
        return new Banana();
    }
}
/**
 * @description: 橙子工厂
 * @author: lmc
 * @create: 2019-03-20 20:19
 **/

public class OrangeFactory implements IFruitsFactory {
    @Override
    public IFruits product() {
        System.out.println("橙子工厂只生产橙子");
        return new Orange();
    }
}
/**
 * @description: 工厂方法测试
 * @author: lmc
 * @create: 2019-03-20 20:39
 **/

public class MethodFactoryTest {

    public static void main(String[] args) {

        IFruitsFactory iFruitsFactory= new AppleFactory();
        iFruitsFactory.product().getName();

        iFruitsFactory = new BananaFactory();
        iFruitsFactory.product().getName();

        iFruitsFactory = new OrangeFactory();
        iFruitsFactory.product().getName();
    }
}

运行结果:

苹果工厂只生产苹果
我是苹果,水果的一种

香蕉工厂只生产香蕉
我是香蕉,水果的一种

橙子工厂只生产橙子
我是橙子,水果的一种

专人做专事,具体的对象只有具体的工厂创建。用户只有选择权,不需要传入参数。对象的实例化推迟到了工厂实现类创建。

利:

  • 专人专事,遵循单一原则,子类工厂实现具体业务。让业务更清晰
  • 遵循开闭原则,新增业务,只需要添加产品类和具体的产品工厂类就可以了,增加产品扩展性。
    • 新增草莓产品,我只需要新增草莓类和草莓工厂就可以了。

弊:

  • 类的个数容易过多,增加复杂度。
  • 增加了系统的抽象性和理解难度。

工厂方法模式类图

技术图片

抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。客户端(应用层)不依赖于产品类实例如何被创建、实现等细节,强调的是一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

现在了解下上面提到的产品族和产品等级结构的概念。

产品族:属于一个产品工厂的所有产品。

产品等级结构:不等产品工厂生产的相同的同类产品。

技术图片

技术图片

现在水果工厂需求再次升级,之前又一个水果接口 IFruits ,那么我们再增加 水果果干接口IDriedFruits 、水果果汁接口 IJuice

/**
 * @description: 水果干产品接口
 * @author: lmc
 * @create: 2019-03-19 21:28
 **/

public interface IDriedFruits {

    void getName();

    void getColor();

    void getTaste();

}

/**
 * @description: 水果果汁品接口
 * @author: lmc
 * @create: 2019-03-19 21:28
 **/

public interface IJuice {

    void getName();

    void getColor();

    void getTaste();

}

现在我们有实现类 苹果汁 AppleJuice 、 苹果干 DriedApple ......

/**
 * @description: 苹果干
 * @author: lmc
 * @create: 2019-03-19 21:33
 **/

public class DriedApple implements IDriedFruits {


    @Override
    public void getName() {

        System.out.println(" 我是苹果干,果干的一种");
    }

    @Override
    public void getColor() {
        System.out.println(" 苹果干大概也是白色的吧");
    }

    @Override
    public void getTaste() {
        System.out.println(" 苹果干没吃过,打个也是酸酸的吧");
    }
}
/**
 * @description: 苹果汁
 * @author: lmc
 * @create: 2019-03-19 21:33
 **/

public class AppleJuice implements IJuice {


    @Override
    public void getName() {
        System.out.println(" 我是苹果汁,果汁的一种");
    }

    @Override
    public void getColor() {
        System.out.println(" 苹果汁大概是白色的吧");
    }

    @Override
    public void getTaste() {
        System.out.println(" 苹果汁酸酸的");
    }
}
/**
 * @description: 香蕉干
 * @author: lmc
 * @create: 2019-05-23 23:06
 **/

public class DriedBanana implements IDriedFruits {
    @Override
    public void getName() {
        System.out.println(" 我是香蕉干,果干的一种");
    }

    @Override
    public void getColor() {
        System.out.println(" 香蕉干大概也是黄色的吧");
    }

    @Override
    public void getTaste() {
        System.out.println(" 香蕉干甜甜的");
    }
}
/**
 * @description: 香蕉汁
 * @author: lmc
 * @create: 2019-05-23 23:10
 **/

public class BananaJuice implements IJuice {
    @Override
    public void getName() {
        System.out.println(" 我是香蕉汁,果汁的一种");
    }

    @Override
    public void getColor() {
        System.out.println(" 香蕉汁大概是白色的吧");
    }

    @Override
    public void getTaste() {
        System.out.println(" 香蕉汁甜甜的");
    }
}
/**
 * @description: 橙子干
 * @author: lmc
 * @create: 2019-05-23 23:08
 **/

public class DriedOrange implements IDriedFruits{
    @Override
    public void getName() {
        System.out.println(" 我是橙子干,果干的一种");
    }

    @Override
    public void getColor() {
        System.out.println(" 橙子干大概也是橙黄色的吧");
    }

    @Override
    public void getTaste() {
        System.out.println(" 香蕉干没吃过 应该是甜甜的");
    }
}
/**
 * @description: 橙汁
 * @author: lmc
 * @create: 2019-05-23 23:12
 **/

public class OrangeJuice implements IJuice {
    @Override
    public void getName() {
        System.out.println(" 我是橙汁,果汁的一种");
    }

    @Override
    public void getColor() {
        System.out.println(" 橙汁是橙色的吧");
    }

    @Override
    public void getTaste() {
        System.out.println(" 橙汁汁酸酸甜甜的");
    }
}

工厂类改造

抽象工厂接口,也可以改成抽象类

/**
 * @description: 抽象工厂
 * @author: lmc
 * @create: 2019-03-21 21:59
 **/

public interface IAbstractFruitsFactory {

    /**
     * @description: 水果生产
     * @return com.lmc.gp12380.pattern.factory.fruits.IFruits
     * @date 2019/5/24 8:33
     * @author lmc
     */
    IFruits productFruits();

    /**
     * @description: 果酱生产
     * @return com.lmc.gp12380.pattern.factory.fruits.IDriedFruits
     * @date 2019/5/24 8:34
     * @author lmc
     */
    IDriedFruits productIDriedFruits();

    /**
     * @description: 果汁生产
     * @return com.lmc.gp12380.pattern.factory.fruits.IJuice
     * @date 2019/5/24 8:34
     * @author lmc
     */
    IJuice productJuice();
}
/**
 * @description: 苹果工厂
 * @author: lmc
 * @create: 2019-03-21 22:02
 **/

public class AppleFactory implements IAbstractFruitsFactory {

    /**
     * @description:苹果生成
     * @return com.lmc.gp12380.pattern.factory.fruits.IFruits
     * @date 2019/5/23 15:14
     * @author lmc
     */
    @Override
    public IFruits productFruits() {
        return new Apple();
    }

    /**
     * @description: 苹果酱生产
     * @return com.lmc.gp12380.pattern.factory.fruits.IDriedFruits
     * @date 2019/5/23 15:15
     * @author lmc
     */
    @Override
    public IDriedFruits productIDriedFruits() {
        return new DriedApple();
    }

    /**
     * @description: 苹果汁生产
     * @return com.lmc.gp12380.pattern.factory.fruits.IJuice
     * @date 2019/5/23 15:15
     * @author lmc
     */
    @Override
    public IJuice productJuice() {
        return new AppleJuice();
    }
}
/**
 * @description: 香蕉工厂
 * @author: lmc
 * @create: 2019-05-24 08:35
 **/

public class BananaFactory implements IAbstractFruitsFactory {

    @Override
    public IFruits productFruits() {
        return new Banana();
    }

    @Override
    public IDriedFruits productIDriedFruits() {
        return new DriedBanana();
    }

    @Override
    public IJuice productJuice() {
        return new BananaJuice();
    }
}
/**
 * @description: 橙子工厂
 * @author: lmc
 * @create: 2019-05-24 08:27
 **/

public class OrangeFactory implements IAbstractFruitsFactory {
    @Override
    public IFruits productFruits() {
        return new Orange();
    }

    @Override
    public IDriedFruits productIDriedFruits() {
        return new DriedOrange();
    }

    @Override
    public IJuice productJuice() {
        return new OrangeJuice();
    }
}

抽象工厂其实是一个产品族,具体的实现抽象工厂类生产的产品实例所产生同一产品类型,比如所有的水果是一个产品等级结构,所有的果酱也是一个产品等级结构,所有的果汁是一个产品等级结构。

/**
 * @description: 抽象工厂方法测试
 * @author: lmc
 * @create: 2019-03-20 20:39
 **/

public class AbstractFactoryTest {

    public static void main(String[] args) {

        AppleFactory appleFactory=new AppleFactory();
        IFruits apple= appleFactory.productFruits();
        apple.getName();
        apple.getColor();
        apple.getTaste();

        IDriedFruits appleDriedFruits=appleFactory.productIDriedFruits();
        appleDriedFruits.getColor();
        appleDriedFruits.getName();
        appleDriedFruits.getTaste();

        IJuice appleJuice=appleFactory.productJuice();
        appleJuice.getName();
        appleJuice.getColor();
        appleJuice.getTaste();

        System.out.println("_________________________________________");
        OrangeFactory orangeFactory=new OrangeFactory();
        IFruits orange= orangeFactory.productFruits();
        orange.getName();
        orange.getColor();
        orange.getTaste();

        IDriedFruits orangeDriedFruits=orangeFactory.productIDriedFruits();
        orangeDriedFruits.getColor();
        orangeDriedFruits.getName();
        orangeDriedFruits.getTaste();

        IJuice orangeJuice=orangeFactory.productJuice();
        orangeJuice.getName();
        orangeJuice.getColor();
        orangeJuice.getTaste();

        System.out.println("_________________________________________");
        BananaFactory bananaFactory=new BananaFactory();
        IFruits banana= bananaFactory.productFruits();
        banana.getName();
        banana.getColor();
        banana.getTaste();

        IDriedFruits bananaDriedFruits=bananaFactory.productIDriedFruits();
        bananaDriedFruits.getColor();
        bananaDriedFruits.getName();
        bananaDriedFruits.getTaste();

        IJuice bananaJuice=appleFactory.productJuice();
        bananaJuice.getName();
        bananaJuice.getColor();
        bananaJuice.getTaste();

    }
}

测试结构

 我是苹果,水果的一种
 苹果干大概也是白色的吧
 我是苹果干,果干的一种
 苹果干没吃过,打个也是酸酸的吧
 我是苹果汁,果汁的一种
 苹果汁大概是白色的吧
 苹果汁酸酸的
_________________________________________
 我是橙子,水果的一种
 橙子干大概也是橙黄色的吧
 我是橙子干,果干的一种
 橙子干没吃过 应该是酸酸甜甜的
 我是橙汁,果汁的一种
 橙汁是橙色的吧
 橙汁汁酸酸甜甜的
_________________________________________
 我是香蕉,水果的一种
 香蕉是黄色的
 香蕉馋起来很甜很滑
 香蕉干大概也是黄色的吧
 我是香蕉干,果干的一种
 香蕉干甜甜的
 我是香蕉汁,果汁的一种
 香蕉汁大概是白色的吧
 香蕉汁甜甜的

抽象工厂利弊

利:

  • 适合复杂业务需求,清晰描述复杂关系。
  • 专职专事,子类实现具体产品族业务。

弊:

  • 违背开闭原则,新增产品族或者产品等级需要修改代码(产品迭代升级是有周期的)
  • 增加系统的抽象性和理解难度。

抽象工厂类图

技术图片

总结

工厂模式是一种面向对象程序封装,属于设计模式的创建型模式。客户端或者调用者需要的对象由工厂创建,不需要知道创建对象复杂的业务逻辑。简单工厂模式到工厂方法模式,再到抽象工厂模式。其实是一种社会进步的表现。

简单工厂就是一个小作坊,只要是工厂有这种产品都可以去生产。这就造成了管理不规范,维护困难。注定的简单工厂就是简单工厂,发展壮大不起来。当是呢方便,就好比你需要一箱牛奶,你去小超市就可以拿了,肯定不需要费九牛二虎之力去大草原找牛去挤奶吧。

工厂方法模式对应流水线生产企业。他们的产品比较少,管理规范,维护简单。这样的公司能够做大,出名,就好像那些只做单一产品的企业,比如服装工厂,塑料工厂。但是呢,产品单一,面临的竞争压力大,面临更复杂的业务束手无策,很容易被别人取而代之。对于新的产品,就要新建工程,新增流水线,投入成本太高。

抽象工厂模式:对应现代化产业链代工厂,生产、管理规范。强调的是产业链,一系列相互关联的产品。形成了一个产品生态。让用户不可或缺,绝对是世界级的大企业,比如华为,以及一些世界500强公司。他面临的是一个产业链的生产管理。抽象工厂模式封装的是复杂的产品关系业务。

以上是关于Java设计模式——工厂模式的主要内容,如果未能解决你的问题,请参考以下文章

JAVA设计模式之工厂模式

java与模式,这段代码怎么反映简单工厂模式了?

java设计模式 GOF23 02 工厂模式

Java设计模式图文代码案例详解Java五大创建者模式 建造者原型(抽象)工厂单例模式

java设计模式--工厂模式

Java 工厂模式