设计模式:工厂设计模式

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

使用场景:

在任何需要生成复杂对象的地方,都可以使用工厂方法模式。
直接用new可以完成的不需要用工厂模式

简单(静态)工厂:

interface Fruit
{
    public void eat();
}
class Apple implements Fruit
{
    public void eat()
    {System.out.println("苹果吃掉");}
}
class Orangle implements Fruit
{
    public void eat()
    {System.out.println("橘子吃掉");}
}
class Factory
{
    public static Fruit getInstance(String str)  //Fruit 是返回类型 这里为什么要用static
    {
    if("Apple".equals(str)){return new Apple();}
    else if("Orangle".equals(str)){return new Orangle();}
    else {return null;}
    }
}
public class JieKouSj
{
    public static void main(String args[])
    {
    Fruit f=Factory.getInstance("Orangle"); //解释上面的static 因为没有static的话 只能Fruit f=new Factory(); 要想调用里面的方法 要把方法独立出来
    f.eat();
    }
}

工厂设计模式就相当于有一个过渡/工厂,需要什么,跟工厂说,工厂返回想得到的东西

特点
1 工厂类是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
2 create()方法通常是静态的,所以也称之为静态工厂。

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

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

public abstract class INoodles {
    /**
     * 描述每种面条啥样的
     */
    public abstract void desc();
}
public class LzNoodles extends INoodles {
    @Override
    public void desc() {
        System.out.println("兰州拉面 上海的好贵 家里才5 6块钱一碗");
    }
}
public class PaoNoodles extends INoodles {
    @Override
    public void desc() {
        System.out.println("泡面好吃 可不要贪杯");
    }
}
public class GankouNoodles extends INoodles {
    @Override
    public void desc() {
        System.out.println("还是家里的干扣面好吃 6块一碗");
    }
}
public class StaticNoodlesFactory {
    /**
     * 传入Class实例化面条产品类 通过反射生成对象返回
     *
     * @param clz
     * @param <T>
     * @return
     */
    public static <T extends INoodles> T createNoodles(Class<T> clz) {
        T result = null;
        try {
            // 相当于通过传入的类使用new调用无参构造实例化
            result = (T) Class.forName(clz.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

main方法:

//兰州拉面
INoodles lz = StaticNoodlesFactory.createNoodles(LzNoodles.class);
lz.desc();
//泡面
INoodles pm = StaticNoodlesFactory.createNoodles(PaoNoodles.class);
pm.desc();

特点
工厂类也是一个具体的类,非接口 抽象类。但它的create()方法,是利用反射机制生成对象返回,好处是增加一种产品时,不需要修改工厂类中create()的代码。
缺点
1 个人觉得不好,因为Class.forName(clz.getName()).newInstance()调用的是无参构造函数生成对象,它和new Object()是一样的性质,而工厂方法应该用于复杂对象的初始化当需要调用有参的构造函数时便无能为力了,这样像为了工厂而工厂。

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

多方法工厂(常用)

上面两种工厂都有一个缺点:不同的产品需要不同额外参数的时候 不支持。也就是不能实现有参的构造函数
而且如果使用时传递的type、Class出错,将不能得到正确的对象,容错率不高。

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

工厂如下:(感觉就像是把所有的都包装一下)

public class MulWayNoodlesFactory {

    /**
     * 模仿Executors 类
     * 生产泡面
     *
     * @return
     */
    public static INoodles createPm() {
        return new PaoNoodles();
    }

    /**
     * 模仿Executors 类
     * 生产兰州拉面
     *
     * @return
     */
    public static INoodles createLz() {
        return new LzNoodles();
    }

    /**
     * 模仿Executors 类
     * 生产干扣面
     *
     * @return
     */
    public static INoodles createGk() {
        return new GankouNoodles();
    }
}

main方法

INoodles lz2 = MulWayNoodlesFactory.createLz();
lz2.desc();
INoodles gk2 = MulWayNoodlesFactory.createGk();
gk2.desc();

输出:

兰州拉面 上海的好贵 家里才5 6块钱一碗
还是家里的干扣面好吃 6块一碗

源码撑腰环节

查看java源码:java.util.concurrent.Executors类便是一个生成Executor 的工厂 ,其采用的便是 多方法静态工厂模式:
例如ThreadPoolExecutor类构造方法有5个参数,其中三个参数写法固定,前两个参数可配置,如下写。

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

又如JDK想增加创建ForkJoinPool类的方法了,只想配置parallelism参数,便在类里增加一个如下的方法:

public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool
            (parallelism,
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

这个例子可以感受到工厂方法的魅力了吧:方便创建 同种类型的 复杂参数 对象。

普通工厂

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

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

public abstract class NoodlesFactory {
    public abstract INoodles create();
}

兰州拉面工厂 (具体工厂子类):

public class LzFactory extends NoodlesFactory {
    @Override
    public INoodles create() {
        return new LzNoodles();
    }
}

泡面工厂 (具体工厂子类):

public class PaoFactory extends NoodlesFactory {
    @Override
    public INoodles create() {
        return new PaoNoodles();
    }
}

干扣面工厂 (具体工厂子类):

public class GankouFactory extends NoodlesFactory {
    @Override
    public INoodles create() {
        return new GankouNoodles();
    }
}

main方法:

NoodlesFactory factory1 = new GankouFactory();
INoodles gk3 = factory1.create();
gk3.desc();

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

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

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

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

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

缺点:

引入抽象工厂层后,每次新增一个具体产品类,也要同时新增一个具体工厂类,所以我更青睐 多方法静态工厂。

抽象工厂:

以上介绍的工厂都是单产品系的。抽象工厂是多产品系 (貌似也有产品家族的说法)。

举个例子来说,每个店(工厂)不仅仅卖面条,还提供饮料卖。
提供饮料卖,饮料是产品,先抽象一个产品类,饮料:

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

然后实现两个具体产品类:
可乐:

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

屌丝还是多喝水吧:

public class WaterDrinks extends IDrinks {
    @Override
    public void prices() {
        System.out.println("和我一样的穷鬼都喝水,不要钱~!");
    }
}

抽象饭店,无外乎吃喝(抽象工厂类):

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

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

兰州大酒店(具体工厂类):

public class LzlmFoodFactory extends AbstractFoodFactory {
    @Override
    public INoodles createNoodles() {
        return new LzNoodles();//卖兰州拉面
    }

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

KFC(具体工厂类):

public class KFCFoodFactory extends AbstractFoodFactory {
    @Override
    public INoodles createNoodles() {
        return new PaoNoodles();//KFC居然卖泡面
    }

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

main方法

AbstractFoodFactory abstractFoodFactory1 = new KFCFoodFactory();
abstractFoodFactory1.createDrinks().prices();
abstractFoodFactory1.createNoodles().desc();

abstractFoodFactory1= new LzlmFoodFactory();
abstractFoodFactory1.createDrinks().prices();
abstractFoodFactory1.createNoodles().desc();

输出:

可乐三块五
泡面好吃 可不要贪杯
和我一样的穷鬼都喝水,不要钱~!
兰州拉面 上海的好贵 家里才5 6块钱一碗

小结:
将工厂也抽象了,在使用时,工厂和产品都是面向接口编程,OO(面向对象)的不得了。

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

个人总结和使用场景

一句话总结工厂模式:方便创建 同种产品类型的 复杂参数 对象

工厂模式重点就是适用于 构建同产品类型(同一个接口 基类)的不同对象时,这些对象new很复杂,需要很多的参数,而这些参数中大部分都是固定的,so,懒惰的程序员便用工厂模式封装之。
(如果构建某个对象很复杂,需要很多参数,但这些参数大部分都是“不固定”的,应该使用Builder模式)

转载:https://blog.csdn.net/zxt0601/article/details/52798423

猜你喜欢

转载自blog.csdn.net/guo_binglo/article/details/80553598