工厂模式有三种:简单工厂模式,工厂方法模式,抽象工厂模式。其中,简单工厂模式不属于 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(); //输出:种植橘子
}
}
复制代码
到这里,想必大家都明白工厂方法和简单工厂的区别了吧。
工厂方法模式的使用场景
工厂方法模式的缺点
每增加一个产品就得需要新增两个类,一旦产品数量上去了,类的个数也会随之增加,这样一来增加了系统的复杂度,也会使得系统过于抽象、难以理解。
评论