工厂模式概述
工厂模式是一种用于创建对象的设计模式,其核心在于把获得某种对象的过程从程序中解耦出来,成为一个单独的模块。
这样做为什么是必要的呢?在一些时候,获得对象只需要一行简单的 new
语句,此时确实没有将其封装的必要;但在实际场景中,创建一个对象的过程也许会更为复杂。
举个例子,假设 A 对象的创建依赖 B 对象和 C 对象:
1 2 3 4 5
| B b = new B();
C c = new C();
A a = new A(b,c);
|
假设有十个模块都用这种方式创建 A 对象,那么如果某天想把 A 对象的创建改为依赖一个 D 对象,我们就只能把这十个模块手动改一遍。
如果我们用了工厂模式的设计思想,把上面的过程封装成到一个工厂类:
1 2 3 4 5 6 7 8 9 10
| public class Factory{ public A CreateA(){ B b = new B(); C c = new C(); A a = new A(b,c); return A; } }
|
而其他模块都通过工厂类来获取A对象:
1 2
| Factory f = new Factory(); A = f.CreateA();
|
那么后续A的创建过程被修改时,我们只要修改Factory
类就可以了。
工厂模式具体实现
工厂模式的思想我们已经清楚了,在实践中,工厂模式大体上有三种实现形式,即:
假设有两个类Phone和Tablet,都继承自抽象类Device,我们来考察不同的工厂模式如何创建所需的对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public abstract class Device{ public abstract void work(); }
public class Phone extends Device{ @Override public void work(){ System.out.println("A phone is working"); } }
public class Tablet extends Device{ @Override public void work(){ System.out.println("A tablet is working"); } }
|
简单工厂模式
这种实现方式定义一个工厂类,在这个类中实现所有对象的创建:
1 2 3 4 5 6 7 8 9 10
| public class DeviceFactory{ public Device createDevice(int deviceType){ if (deviceType == 0) { return new Phone(); } else if (deviceType == 1) { return new Tablet(); } return null; } }
|
这样写的优点在于不必在原有基础上添加过多的代码,而且便于控制创建不同对象的逻辑。比如游戏中敌人被击败时掉落道具的代码,创建何种道具对象的逻辑可能十分复杂,就适合采用此种方式。
而此方法的缺点是,后续增加对象时,不得不修改现有的代码,系统的可扩展性一般。
工厂方法模式
此方法定义一个创建对象的抽象接口,用不同的子类实现创建具体对象的方法:
1 2 3
| public interface DeviceFactory{ Device createDevice(); }
|
1 2 3 4 5 6
| public class PhoneFactory implements DeviceFactory{ @Override public Device createDevice(){ return new Phone(); } }
|
1 2 3 4 5 6
| public class TabletFactory implements DeviceFactory{ @Override public Device createDevice(){ return new Tablet(); } }
|
这种方式的优点是后续增加对象时,不需要修改已有代码,只需增加新的子类,整个项目架构十分清晰,可扩展性高。
缺点也是明显的,即代码量大,而且本身无法实现不同对象创建的逻辑,只关注于对象的创建过程本身。
抽象工厂模式
上面提到的工厂方法模式,其工厂只负责创建一种对象,而此种模式下一种工厂负责创建一类对象。
在上面举的例子中,我们把Phone和Tablet改为抽象类,并为它们添加子类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public abstract class Phone extends Device{
}
public class HuaweiPhone extends Phone{ @Override public void work(){ System.out.println("A HuaweiPhone is working"); } }
public class XiaomiPhone extends Phone{ @Override public void work(){ System.out.println("A XiaomiPhone is working"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public abstract class Tablet extends Device{ }
public class HuaweiTablet extends Tablet{ @Override public void work(){ System.out.println("A HuaweiPhone is working"); } }
public class XiaomiTablet extends Tablet{ @Override public void work(){ System.out.println("A XiaomiTablet is working"); } }
|
对于四种对象,如果用工厂方法模式,需要四种工厂。但这四种对象继承自两种抽象类,这意味着我们其实可以用两种工厂完成创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public interface DeviceFactory{ Phone createPhone(); Tablet createTablet(); }
public class HuaweiFactory implements DeviceFactory{ @Override public Phone createPhone(){ return new HuaweiPhone(); }
@Override public Tablet createTablet(){ return new HuaweiTablet(); } }
public class XiaomiFactory implements DeviceFactory{ @Override public Phone createPhone(){ return new XiaomiPhone(); }
@Override public Tablet createTablet(){ return new XiaomiTablet(); } }
|
这就是所谓抽象工厂模式,其本质是对工厂进行了一层抽象:把原来所需的四种工厂,根据创建对象的某些共性抽象为两种。此方法适用于对象有较多继承关系的场景,可以减少工厂方法模式需要的工厂数量。缺点是扩展性弱,例如后续增加一个earphone抽象类,就需要修改所有工厂类。
总结
工厂模式体现了面向对象中“各司其职”的思想,是为了把复杂的业务逻辑划分到不同模块,降低耦合程度,以提高代码的复用性,便于开发和后期维护。