工厂模式有三种:简单工厂模式,工厂方法模式,抽象工厂模式。其中,简单工厂模式不属于 23 中设计模式。本篇文章会通过从简单工厂模式过渡到工厂方法模式的方式呈现。
一、简单工厂模式
简单工厂模式(Simple Factory Pattern):指的是由一个工厂对象来决定创建具体的产品实例,简单工厂模式并不属于 23 中设计模式,但是在我们平常运用的非常广泛。
下面我通过一个农场里面种植水果来举例实现简单工厂模式。
package cn.liangyy.simple;
/** * 产品接口 */public interface IProduct { /** * 种植水果 */ void grow();}
复制代码
package cn.liangyy.simple;
/** * 苹果类 */public class Apple implements IProduct { /** * 种植水果 */ @Override public void grow() { System.out.println("种植苹果"); }}
复制代码
package cn.liangyy.simple;
/** * 橘子类 */public class Orange implements IProduct { /** * 种植水果 */ @Override public void grow() { System.out.println("种植橘子"); }}
复制代码
按照我们普通的写法,如果创建 Apple 和 Orange 对象的话,直接 new 出来就好了,但是这种方式很不友好,一旦一个对象的创建非常复杂,就会给我们带来极大的不方便,所以我们新建一个工厂类来帮助我们创建具体的产品类,从而隐藏创建对象的细节。
package cn.liangyy.simple;
/** * 简单工厂类 */public class SimpleFactory { public IProduct createProduct(String productType){ if ("apple".equals(productType)){ return new Apple(); }else if ("orange".equals(productType)){ return new Orange(); } return null; }}
复制代码
package cn.liangyy.simple;
/** * 简单工厂-测试类 */public class TestSimpleFactory { public static void main(String[] args) { SimpleFactory factory = new SimpleFactory(); IProduct apple = factory.createProduct("apple"); apple.grow(); //输出:种植苹果
IProduct orange = factory.createProduct("orange"); orange.grow(); //输出:种植橘子 }}
复制代码
这时候我们就将创建细节隐藏了,全部产品都通过 SimpleFactory 来帮忙创建,但是这种写法依旧存在问题:
1、假如我调用 createProduct()方法参数写错了,比如 apple 拼错了,这时候代码编译时可以通过的,运行时才能发现问题。
2、 如果产品很多,那么 SimpleFactory 类中就会产生大量的 if 分支,效率降低
所以为了解决这个问题,我们再优化一下 SimpleFactory 类中的 createProduct()方法。
package cn.liangyy.simple;
/** * 简单工厂类 */public class SimpleFactory { /** * 普通方法 * @param productType * @return */ public IProduct createProduct(String productType){ if ("apple".equals(productType)){ return new Apple(); }else if ("orange".equals(productType)){ return new Orange(); } return null; }
/** * 优化方法 * @param clazz * @return * @throws Exception */ public IProduct createProduct2(Class<? extends IProduct> clazz) throws Exception { if (null == clazz){ throw new Exception("无法识别的产品"); } return clazz.newInstance(); }}
复制代码
package cn.liangyy.simple;
/** * 简单工厂-测试优化后的方法 */public class TestSimpleFactory2 { public static void main(String[] args) throws Exception { SimpleFactory factory = new SimpleFactory(); IProduct apple = factory.createProduct2(Apple.class); apple.grow(); //输出:种植苹果
IProduct orange = factory.createProduct2(Orange.class); orange.grow(); //输出:种植橘子 }}
复制代码
由上可以看出,这种写法完美的解决了第一种存在的问题(不过需要强调的是,我们的工厂类一般要将创建对象实例的方法设置成静态方法)。
简单工厂模式使用场景
适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心。
简单工厂模式存在的问题
假如每种产品创建不仅仅只是实例化一个对象,还有其它逻辑需要处理,那么我们无法直接使用一句反射语句来创建对象,所以还是避免不了要写很多 if 或者 switch 循环分支。这样每新增一个产品我们都需要修改简单工厂类,违背了开闭原则,而且随着产品越来越丰富,工厂的职责会变得越来越多,久而久之会越来越难以维护。
为了弥补简单工厂方法的不足之处,所以就有了工厂方法模式。
二、工厂方法模式
工厂方法模式:Fatory Method Pattern,主要用来解决简单工厂模式存在的问题。其是指定义一个创建对象的接口,然后创建不同的具体工厂来创建对应的产品。工厂方法让类的实例化推迟到工厂子类中进行,在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节。
工厂方法模式中假如需要新增产品,只需要再新建工厂实现类,无需修改源码,符合开闭原则。
我们依旧通过农场里面种植水果来实现工厂方法模式。
package cn.liangyy.method;
/** * 产品接口 */public interface IProduct { void grow();}
复制代码
package cn.liangyy.method;
/** * 苹果类 */public class Apple implements IProduct { @Override public void grow() { System.out.println("种植苹果"); }}
复制代码
package cn.liangyy.method;
/** * 橘子类 */public class Orange implements IProduct { @Override public void grow() { System.out.println("种植橘子"); }}
复制代码
package cn.liangyy.method;
/** * 工厂接口 */public interface IFarmFactory { /** * 创建产品 * @return */ IProduct create();}
复制代码
package cn.liangyy.method;
/** * 苹果工厂 */public class AppleFactory implements IFarmFactory { /** * 创建产品 * * @return */ @Override public IProduct create() { return new Apple(); }}
复制代码
package cn.liangyy.method;
/** * 橘子工厂 */public class OrangeFactory implements IFarmFactory { /** * 创建产品 * * @return */ @Override public IProduct create() { return new Orange(); }}
复制代码
package cn.liangyy.method;
/** * 工厂方法测试类 */public class TestFactoryMethod { public static void main(String[] args) { IFarmFactory appleFactory = new AppleFactory(); IProduct apple = appleFactory.create(); apple.grow(); //输出:种植苹果
IFarmFactory orangeFactory = new OrangeFactory(); IProduct orange = orangeFactory.create(); orange.grow(); //输出:种植橘子 }}
复制代码
到这里,想必大家都明白工厂方法和简单工厂的区别了吧。
工厂方法模式的使用场景
工厂方法模式的缺点
每增加一个产品就得需要新增两个类,一旦产品数量上去了,类的个数也会随之增加,这样一来增加了系统的复杂度,也会使得系统过于抽象、难以理解。
评论