• 欢迎访问1024小神,一个只会Python的程序猿不是一个好司机
  • 有什么想对我说的可以在留言板里给我留言哦~
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏1024小神吧

工厂模式(简单、普通、抽象)

C other 1024小神 1年前 (2020-12-28) 396次浏览 3个评论

概述

属于创建型设计模式,需要生成的对象叫做产品 ,生成对象的地方叫做工厂 。

使用场景:

1、在任何需要生成复杂对象的地方,都可以使用工厂方法模式。

2、直接用new可以完成的不需要用工厂模式

一、简单(静态)工厂

我喜欢吃粉,抽象一个粉基类(或者接口),这是产品的抽象类

package com.wbg.FactoryMode;

public abstract class Powder {
    /**
     * 描述粉
     * 桂林米粉、柳州螺蛳粉
     */
    public abstract void desc();
}

来一份桂林米粉(具体的产品类)

package com.wbg.FactoryMode;

public class GlPowder extends Powder {
    @Override
    public void desc() {
        System.out.println("桂林米粉,很好吃,上海的很贵,在家才5-6块钱");
    }
}

我老家的螺蛳粉(具体的产品类)

package com.wbg.FactoryMode;

public class LsfPowder extends Powder {

    @Override
    public void desc() {
        System.out.println("螺蛳粉,不错,老家6块钱,珠海10多块");
    }
}

准备工作做完了,我们来到一家“粉店”(简单工厂),菜单如下:

package com.wbg.FactoryMode;

public class SimplePowderFactor {
    public static final int TYPE_LZ = 1;//桂林米粉
    public static final int TYPE_PM = 2;//螺蛳粉
    public static Powder createNoodles(int type) {
    if(type==1){
        return new GlPowder();
    }else {
        return new LsfPowder();
    }
    }
}

简单粉店就提供二种面条(产品),你说你要啥,他就给你啥。这里我点了桂林米粉:

package com.wbg.FactoryMode;

/**
 * 简单工厂模式
 */
public class Customer {
    public static void main(String[] args) {
        Powder powder=SimplePowderFactor.createNoodles(SimplePowderFactor.TYPE_LZ);
        powder.desc();
    }
}

特点

1、 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。

2、 create()方法通常是静态的,所以也称之为静态工厂

缺点

1、 扩展性差(我想增加一种粉,除了新增一个粉产品类,还需要修改工厂类方法)

2 、不同的产品需要不同额外参数的时候 不支持。

二、另一种简单工厂(反射):

利用反射Class.forName(tClass.getName()).newInstance()实现的简单工厂

package com.wbg.FactoryMode;

public class StaticPowderFactor {
    /**
     * 传入Class实例化粉产品类
     *
     * @param tClass
     * @param <T>
     * @return
     */
    public static <T extends Powder>T createPowder(Class<T> tClass){
        T result=null;
        try {
            result= (T) Class.forName(tClass.getName()).newInstance();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return result;
    }
}

点粉:

package com.wbg.FactoryMode;

public class Customer {
    public static void main(String[] args) {
        Powder powder=StaticPowderFactor.createPowder(new LsfPowder().getClass());
        powder.desc();
    }
}

特点

1 它也是一个具体的类,非接口 抽象类。但它的create()方法,是利用反射机制生成对象返回,好处是增加一种产品时,不需要修改create()的代码。

缺点

1 因为Class.forName(clz.getName()).newInstance()调用的是无参构造函数生成对象,它和new Object()是一样的性质,而工厂方法应该用于复杂对象的初始化 ,当需要调用有参的构造函数时便无能为力了,这样像为了工厂而工厂。

2 不同的产品需要不同额外参数的时候 不支持。

三、多方法工厂

上面都有一个缺点:不同的产品需要不同额外参数的时候 不支持。

如果使用时传递的type、Class出错,将不能得到正确的对象,容错率不高。

多方法的工厂模式为不同产品,提供不同的生产方法,使用时 需要哪种产品就调用该种产品的方法,使用方便、容错率高。

工厂:

package com.wbg.FactoryMode;

public class VariedPowderFactor {
    /**
     * 生产桂林米粉
     * @return
     */
    public static Powder createGl(){
        return new GlPowder();
    }
    /**
     * 生产螺丝粉
     * @return
     */
    public static Powder createLsf(){
        return new LsfPowder();
    }
}

点餐:

package com.wbg.FactoryMode;

public class Customer {
    public static void main(String[] args) {
        Powder glpowder=VariedPowderFactor.createGl();
        glpowder.desc();

        Powder lsfpowder=VariedPowderFactor.createLsf();
        lsfpowder.desc();
    }
}

四、普通工厂

普通工厂就是把简单工厂中具体的工厂类,划分成两层:抽象工厂层+具体的工厂子类层。(一般->特殊)

工厂(抽象工厂类),作用就是生产粉:

package com.wbg.FactoryMode;

public abstract  class PowderFactory {
    public abstract Powder create();
}

我老家的螺蛳粉(具体工厂子类):

package com.wbg.FactoryMode;

public class createLsfFactory extends PowderFactory {
    @Override
    public Powder create() {
        return new LsfPowder();
    }
}

桂林米粉(具体工厂子类):

package com.wbg.FactoryMode;

public class createGlFactory extends PowderFactory{
    @Override
    public Powder create() {
        return new GlPowder();
    }
}

使用:

package com.wbg.FactoryMode;

public class Customer {
    public static void main(String[] args) {
       PowderFactory factory=new createGlFactory();
       Powder powder=factory.create();
       powder.desc();
    }
}

普通工厂与简单工厂模式的区别:

可以看出,普通工厂模式特点:不仅仅做出来的产品要抽象, 工厂也应该需要抽象。

工厂方法使一个产品类的实例化延迟到其具体工厂子类.

工厂方法的好处就是更拥抱变化。当需求变化,只需要增删相应的类,不需要修改已有的类。

简单工厂需要修改工厂类的create()方法,多方法静态工厂模式需要增加一个静态方法。

缺点:

引入抽象工厂层后,每次新增一个具体产品类,也要同时新增一个具体工厂类!

抽象工厂

以上介绍的工厂都是单产品系的。抽象工厂是多产品系 。

每个粉店(工厂)不仅仅卖粉,还提供饮料卖。
提供饮料卖,饮料是产品,先抽象一个产品类,饮料:

public abstract class IDrinks {
    /**
     * 描述每种饮料多少钱
     */
    public abstract void prices();
}

可乐:

public class ColaDrinks extends IDrinks {
    @Override
    public void prices() {
        System.out.println("可乐1块钱");
    }
}

水:

public class WaterDrinks extends IDrinks {
    @Override
    public void prices() {
        System.out.println("太辣了,我要和免费水");
    }
}

抽象粉店(抽象工厂类):

public abstract class AbstractFoodFactory {
    /**
     * 生产面条
     *
     * @return
     */
    public abstract Powder createPowder();

    /**
     * 生产饮料
     */
    public abstract IDrinks createDrinks();
}

柳州螺蛳粉(具体工厂类):

public class LsflmFoodFactory extends AbstractFoodFactory {
    @Override
    public Powder createPowder() {
        return new LsfPowder();//螺蛳粉
    }

    @Override
    public IDrinks createDrinks() {
        return new WaterDrinks();//卖水
    }
}

酒店(具体工厂类):

public class hodelFoodFactory extends AbstractFoodFactory {
    @Override
    public Powder createPowder() {
        return new GlPowder();//桂林米粉很好吃,酒店都有了
    }

    @Override
    public IDrinks createDrinks() {
        return new ColaDrinks();//卖可乐
    }
}

使用:

 AbstractFoodFactory abstractFoodFactory1 = new hodelFoodFactory();
        abstractFoodFactory1.createDrinks().prices();
        abstractFoodFactory1.createPowder().desc();


        AbstractFoodFactory abstractFoodFactory2 = new LsflmFoodFactory();
        abstractFoodFactory2.createDrinks().prices();
        abstractFoodFactory2.createPowder().desc()

缺点

将工厂也抽象后,有个显著问题,就是类爆炸了。而且每次拓展新产品种类,例如不仅卖吃卖喝,我还想卖其他,这需要修改抽象工厂类,因此所有的具体工厂子类,都被牵连,需要同步被修改。

demo: https://github.com/weibanggang/Factorydemo


如有失效,请留言告知丨转载请注明原文链接:工厂模式(简单、普通、抽象)
点赞 (0)

您必须 登录 才能发表评论!

(3)个小伙伴在吐槽
  1. rootroot99
    直接new想要得class不香吗,干嘛要调用这么多层才达到最终目的
    2021-12-28 17:15
  2. Jason
    https://segmentfault.com/a/1190000038463122. vue集成electron插件
    2021-01-14 10:03
  3. 木木vip
    好几天没过来看看了,今天来报个到,顺便偷剽一小段代码 嘿嘿
    2020-12-31 12:02