简述
-
类型:创建型
-
目的:实现对客户端中对象的平替。
我们借以下案例来说说如何使用工厂方法模式平替对象。
优化案例
最初版
public interface OS { public void start(); public void sleep(); public void restart(); public void stop(); } public class Linux implements OS { public void start() { System.out.println("启动Linux系统!"); } public void sleep() { System.out.println("睡眠Linux系统!"); } public void restart() { System.out.println("重启Linux系统!"); } public void stop() { System.out.println("停止Linux系统!"); } } public class Windows implements OS { public void start() { System.out.println("启动Windows系统!"); } public void sleep() { System.out.println("睡眠Windows系统!"); } public void restart() { System.out.println("重启Windows系统!"); } public void stop() { System.out.println("停止Windows系统!"); } } public class Unix implements OS { public void start() { System.out.println("启动Unix系统!"); } public void sleep() { System.out.println("睡眠Unix系统!"); } public void restart() { System.out.println("重启Unix系统!"); } public void stop() { System.out.println("停止Unix系统!"); } }
客户端调用如下。
public class Client { public static void main(String[] args) { OS os1 = new Linux(); OS os2 = new Windows(); OS os3 = new Unix(); } }
传统是new创建对象的方式有着硬编码的问题。当我们需要把所有Linux对象改为Unix对象时,就必须在项目中检索所有的Linux一一修改为Unix。这无疑增加了大量的无意义的工作。
修改版v1(简单工厂模式)
增加一个工厂类,其他不变。
public class OSFactory { static OS instance(String arg) { if (arg.equals("Linux")) { return new Linux(); } else if (arg.equals("Unix")) { return new Unix(); } else if (arg.equals("Windows")) { return new Windows(); } throw new Exception("输入的参数错误"); } }
修改后,客户端的代码调用。
public class Client { public static void main(String[] args) { OS os1 = OSFactory.instance("Linux"); OS os2 = OSFactory.instance("Windows"); OS os3 = OSFactory.instance("Unix"); } }
在一定程度上解决了客户端硬编码问题。并且当我们需要把所有Linux对象改为Unix对象时,只需要在OS中将new Linux() → new Unix()
即可。这无疑节省了很多的时间,也无需为硬编码带来的大量改修而苦恼。
但是目前这个优化方案依然有至少两个问题,一是OSFactory.instance
方法中耦合了所有的OS实现类,这可能有碍于未来的项目维护,二是new Linux() → new Unix()
这种修改方式会导致代码变得不明确,既然不论是Linux还是Unix都直接生成Unix对象,就没有必要定义Linux了呀。实际上是因为客户端代码中还有使用OSFactory.instance("Linux")
来创建的对象,为了不修改客户端代码,强行做如上修改。
修改版v2(工厂方法模式)
将原本的工厂类抽象化,并定义一系列不同的实现类,其余不变。
public interface OSFactory { OS create(); } public class LinuxFactory { public OS create() { return new Linux(); } } public class WindowsFactory { public OS create() { return new Windows(); } } public class UnixFactory { public OS create() { return new Unix(); } }
修改后,客户端的代码调用。
public class Client { public static void main(String[] args) { OSFactory factory = new LinuxFactory(); OS os1 = factory.create(); } }
将原本OSFactory
类中臃肿的逻辑分散到各个子类中,提高了系统的可维护性,不用再每次都修改Factory类了。
那么,问题来了,这样的结构对于我们的项目有什么帮助吗?几乎没有,我们只是将对象的创建统一管理了而已,这也只是工厂方法模式的一个很小的功能。实际上需求是快速的将系统中的对象平替。而为了实现这个需求,我们需要结合Java反射这项技术。请看下面的代码。
修改版v3(工厂方法+反射)
只修改客户端的调用方式,其他位置不做修改。
public class Client { public static void main(String[] args) { // 实际项目中一般定义成特定的类(专门用来加载各种配置)中的静态变量 Properties prop = new Properties(); FileReader fileReader = new FileReader("src/resource/props/config.prop"); // 使用properties文件来存储当前调用类的信息 prop.load(fileReader); fileReader.close(); OSFactory factory = (OSFactory) Class.forName(prop.getProperty("FACTORY")) .getDeclaredConstructor().newInstance(); OS os1 = factory.create(); } }
增加一个properties文件文件,定义如下。
#当前使用的工厂类 FACTORY=design.factorymethod.demo02.LinuxFactory
当系统需要将实例的LinuxFactory
类转化为其他的实现类时,只需要更改上述配置文件即可。
总结
优点
- 轻松做到类的平替。
缺点
- 类数量倍增,系统复杂度增加。
应用场景
- 根据需求,需要全面替换系统中的某个类时。