设计模式---工厂方法模式

打印 上一主题 下一主题

主题 814|帖子 814|积分 2442

简述


  • 类型:创建型
  • 目的:实现对客户端中对象的平替
我们借以下案例来说说如何使用工厂方法模式平替对象。
优化案例

最初版
  1. public interface OS {
  2.     public void start();
  3.     public void sleep();
  4.     public void restart();
  5.     public void stop();
  6. }
  7. public class Linux implements OS {
  8.     public void start() {
  9.         System.out.println("启动Linux系统!");
  10.     }
  11.     public void sleep() {
  12.         System.out.println("睡眠Linux系统!");
  13.     }
  14.     public void restart() {
  15.         System.out.println("重启Linux系统!");
  16.     }
  17.     public void stop() {
  18.         System.out.println("停止Linux系统!");
  19.     }
  20. }
  21. public class Windows implements OS {
  22.     public void start() {
  23.         System.out.println("启动Windows系统!");
  24.     }
  25.     public void sleep() {
  26.         System.out.println("睡眠Windows系统!");
  27.     }
  28.     public void restart() {
  29.         System.out.println("重启Windows系统!");
  30.     }
  31.     public void stop() {
  32.         System.out.println("停止Windows系统!");
  33.     }
  34. }
  35. public class Unix implements OS {
  36.     public void start() {
  37.         System.out.println("启动Unix系统!");
  38.     }
  39.     public void sleep() {
  40.         System.out.println("睡眠Unix系统!");
  41.     }
  42.     public void restart() {
  43.         System.out.println("重启Unix系统!");
  44.     }
  45.     public void stop() {
  46.         System.out.println("停止Unix系统!");
  47.     }
  48. }
复制代码
客户端调用如下。
  1. public class Client {
  2.     public static void main(String[] args) {
  3.         OS os1 = new Linux();
  4.         OS os2 = new Windows();
  5.         OS os3 = new Unix();
  6.     }
  7. }
复制代码
传统是new创建对象的方式有着硬编码的问题。当我们需要把所有Linux对象改为Unix对象时,就必须在项目中检索所有的Linux一一修改为Unix。这无疑增加了大量的无意义的工作。
修改版v1(简单工厂模式)

增加一个工厂类,其他不变。
  1. public class OSFactory {
  2.     static OS instance(String arg) {
  3.         if (arg.equals("Linux")) {
  4.             return new Linux();
  5.         } else if (arg.equals("Unix")) {
  6.             return new Unix();
  7.         } else if (arg.equals("Windows")) {
  8.             return new Windows();
  9.         }
  10.         throw new Exception("输入的参数错误");
  11.     }
  12. }
复制代码
修改后,客户端的代码调用。
  1. public class Client {
  2.     public static void main(String[] args) {
  3.         OS os1 = OSFactory.instance("Linux");
  4.         OS os2 = OSFactory.instance("Windows");
  5.         OS os3 = OSFactory.instance("Unix");
  6.     }
  7. }
复制代码
在一定程度上解决了客户端硬编码问题。并且当我们需要把所有Linux对象改为Unix对象时,只需要在OS中将new Linux() → new Unix()即可。这无疑节省了很多的时间,也无需为硬编码带来的大量改修而苦恼。
但是目前这个优化方案依然有至少两个问题,一是OSFactory.instance方法中耦合了所有的OS实现类,这可能有碍于未来的项目维护,二是new Linux() → new Unix()这种修改方式会导致代码变得不明确,既然不论是Linux还是Unix都直接生成Unix对象,就没有必要定义Linux了呀。实际上是因为客户端代码中还有使用OSFactory.instance("Linux")来创建的对象,为了不修改客户端代码,强行做如上修改。
修改版v2(工厂方法模式)

将原本的工厂类抽象化,并定义一系列不同的实现类,其余不变。
  1. public interface OSFactory {
  2.            OS create();
  3. }
  4. public class LinuxFactory {
  5.     public OS create() {
  6.         return new Linux();
  7.     }
  8. }
  9. public class WindowsFactory {
  10.     public OS create() {
  11.         return new Windows();
  12.     }
  13. }
  14. public class UnixFactory {
  15.     public OS create() {
  16.         return new Unix();
  17.     }
  18. }
复制代码
修改后,客户端的代码调用。
  1. public class Client {
  2.     public static void main(String[] args) {
  3.         OSFactory factory = new LinuxFactory();
  4.         OS os1 = factory.create();
  5.     }
  6. }
复制代码
将原本OSFactory类中臃肿的逻辑分散到各个子类中,提高了系统的可维护性,不用再每次都修改Factory类了。
那么,问题来了,这样的结构对于我们的项目有什么帮助吗?几乎没有,我们只是将对象的创建统一管理了而已,这也只是工厂方法模式的一个很小的功能。实际上需求是快速的将系统中的对象平替。而为了实现这个需求,我们需要结合Java反射这项技术。请看下面的代码。
修改版v3(工厂方法+反射)

只修改客户端的调用方式,其他位置不做修改。
  1. public class Client {
  2.     public static void main(String[] args) {
  3.         // 实际项目中一般定义成特定的类(专门用来加载各种配置)中的静态变量
  4.         Properties prop = new Properties();
  5.         FileReader fileReader = new FileReader("src/resource/props/config.prop");
  6.         // 使用properties文件来存储当前调用类的信息
  7.         prop.load(fileReader);
  8.         fileReader.close();
  9.         OSFactory factory = (OSFactory) Class.forName(prop.getProperty("FACTORY"))
  10.                                              .getDeclaredConstructor().newInstance();
  11.         OS os1 = factory.create();
  12.     }
  13. }
复制代码
增加一个properties文件文件,定义如下。
  1. #当前使用的工厂类
  2. FACTORY=design.factorymethod.demo02.LinuxFactory
复制代码
当系统需要将实例的LinuxFactory类转化为其他的实现类时,只需要更改上述配置文件即可。
总结

优点


  • 轻松做到类的平替。
缺点


  • 类数量倍增,系统复杂度增加。
应用场景


  • 根据需求,需要全面替换系统中的某个类时。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

吴旭华

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表