一篇搞懂工厂模式的实战应用

3,344 阅读6分钟

一、前言

  由于近期项目实在太忙,导致木有继续更新,今天缓过来了。这一期主要是设计模式实战的一些应用,由于自己在重构项目时,看到之前的老代码实在是惨不忍睹,所以打算优化一波,那么设计模式是很好的选择,会先写工厂模式======>>>>策略模式,然后应用这几种模式来解决项目里面的究极老代码======= if else ......

二、概述

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

2.1 使用场景

  在任何需要生成复杂对象的场景,都可以使用工厂模式。划重点直接用new可以完成的不需要用工厂模式

下面逐个介绍我所知道的各种工厂模式以及它们的特点,使用场景,并尽可能的找出JDK里它们的身影。

三、简单(静态)工厂

3.1 举栗子

  我们经常会去餐馆吃面,那么我们用工厂模式的思维去思考,可以理解为:不同的面条就是产品,而餐馆就是一个工厂

  首先来一个产品的抽象类

package com.MyMineBug.demoRun.factory;

public abstract class INoodles {
	
	/**
	 * 不同面条的描述
	 */
	public abstract void desc();

}

再来一份兰州拉面(具体的实现类

package com.MyMineBug.demoRun.factory;

public class LzNoodles extends INoodles{

	@Override
	public void desc() {
		System.out.println("兰州拉面 深圳的好贵,想吃家里的热干面!");
		
	}

}

程序猿加完班后,必备泡面(具体的实现类

package com.MyMineBug.demoRun.factory;

public class PaoNoodles extends INoodles{

	@Override
	public void desc() {
		System.out.println("不多说,程序员加班必备,回家吃泡面!");
		
	}

}

还有最爱吃老家的热干面(具体的实现类

package com.MyMineBug.demoRun.factory;

public class HotNoodles extends INoodles{

	@Override
	public void desc() {
		System.out.println("还是家里的热干面好吃,又便宜,5快一碗!");
		
	}

}

面条原料都准备好了,接下来就要进入面馆(简单工厂)去点餐了,面馆菜单如下:

package com.MyMineBug.demoRun.factory;

public class SimpleNoodlesFactory {
	
	public static final int TYPE_LZ = 1; //兰州拉面
	
	public static final int TYPE_HOT = 2; //热干面
	
	public static final int TYPE_PAO = 3; //泡面
	
	public static INoodles createNoodies(int type) {
		switch (type) {
		case TYPE_LZ:
			return new LzNoodles();
		case TYPE_PAO:
			return new PaoNoodles();
		default:
			return new HotNoodles();
		}
	}
	

}

这个简单面馆(简单工厂)里面,就只有三种面条(产品),那么你可以想点你喜欢吃的面条,比如我,老板来份热干面:

package com.MyMineBug.demoRun.factory;

public class TestSimpleFactory {
	
	public static void main(String[] args) {
		INoodles nodies = SimpleNoodlesFactory.createNoodies(3);
		nodies.desc();
	}

}

输出如下:

还是家里的热干面好吃,又便宜,5快一碗!

3.2 特点

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

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

3.3 缺点

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

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

3.4 工厂类实现的另外一种方式----(反射)

这里贴一下代码,其实原理跟上面一样,跟new Object()性质是一样的;主要是用Class.forName(clz.getName()).newInstance() 代码如下:

package com.MyMineBug.demoRun.factory;

public class ReflectNoodiesFactory {
	
	public static <T extends INoodles> T createNoodles(Class<T> clz) {
		T result  = null;
		try {
			result = (T) Class.forName(clz.getName()).newInstance();
		} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}

}

三、多方法工厂

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

package com.MyMineBug.demoRun.factory;

public class ManyWayNoodlesFactory {

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

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

    /**
     * 模仿Executors 类
     * 生产热干面
     *
     * @return
     */
    public static INoodles createHOT() {
        return new HotNoodles();
    }
}

输出如下:

==============================模仿Executor类==============================
这种我比较青睐,增加一个新面条,只要去增加一个static方法即可,也不修改原方法逻辑
兰州拉面 深圳的好贵,想吃家里的热干面!
还是家里的热干面好吃,又便宜,5快一碗!

3.1 JDK 相关源码实现多方法工厂模式

大家在使用多线程时应该会经常使用这些方法吧,如果看过源码也了解设计模式之工厂模式,那么对这些类应该很熟悉的。

个人的话,比较推荐使用这种方法作为工厂。

三、普通工厂

  普通工厂就是把简单工厂中具体的工厂类,划分成两层:抽象工厂层+具体的工厂子类层

3.1 举栗子

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

package com.MyMineBug.demoRun.factory;

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

}

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

package com.MyMineBug.demoRun.factory;

public class LzNoodlesFactory extends NoodlesFactory{

	@Override
	public INoodles create() {
		return new LzNoodles();
	}

}

后面俩个具体实现工厂类似,就不贴代码了,接下来看使用时的代码:

package com.MyMineBug.demoRun.factory;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class TestSimpleFactory {
	
	public static void main(String[] args) {
//		INoodles nodies = SimpleNoodlesFactory.createNoodies(2);
//		nodies.desc();
		
	    /**
                        * 多方法静态工厂(模仿Executor类)
         */
//        System.out.println("==============================模仿Executor类==============================" +
//                "\n 这种我比较青睐,增加一个新面条,只要去增加一个static方法即可,也不修改原方法逻辑");
//        INoodles lz2 = ManyWayNoodlesFactory.createLz();
//        lz2.desc();
//        String ssString = null;
//        INoodles gk2 = ManyWayNoodlesFactory.createHOT();
//        gk2.desc();
        
        /**
         * 普通工厂方法:
         */
        System.out.println("===========================普通工厂方法==============================" +
                "\n 这种要多写一个类,不过更面向对象吧 = = ,实际中我更倾向于使用【模仿Executor类】的方式");
        NoodlesFactory factory1 = new LzNoodlesFactory();
        INoodles gk3 = factory1.create();
        gk3.desc();
	}

}

输出:

===========================普通工厂方法==============================
 这种要多写一个类,不过更面向对象吧 = = ,实际中我更倾向于使用【模仿Executor类】的方式
兰州拉面 深圳的好贵,想吃家里的热干面!

3.2 优缺点

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

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

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

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

个人推荐使用多方法静态工厂

四、抽象工厂

  抽象工厂其实可以理解为,多产品的多抽象工厂,比如:举个例子来说,每个店(工厂)不仅仅卖面条,还提供饮料卖,那么就会维护多个工厂,需要把工厂抽象出来,而且每次拓展新产品种类,例如不仅卖吃卖喝,我还想卖睡,提供床位服务,这需要修改抽象工厂类,因此所有的具体工厂子类,都被牵连,需要同步被修改。 这里具体实现,我就不贴代码,读者自行百度,因为这次优化代码也没用到这个。

五、总结

  一句话总结工厂模式:方便创建 同种产品类型的 复杂参数 对象。具体使用可以根据实际业务场景进行选择使用,工厂模式的理解到此为止,写一篇会讲一下策略模式。

  如果觉得还不错,请点个赞!!!

  Share Technology And Love Life