编写工厂类和配置文件

919 阅读5分钟

为了满足“开闭原则”,大部分设计模式都引入了抽象层,如工厂方法模式、抽象工厂模式、适配器模式、桥接模式、命令模式、策略模式等等。客户端代码针对抽象层编程,而在程序运行的时候再指定其子类,根据“里氏代换原则”和面向对象的多态性,子类对象在运行时将覆盖父类对象。如果需要对系统进行扩展或修改,只需修改子类类名即可。在具体实现时,通过引入配置文件可以使得用户在不修改任何客户端代码的前提下增加或替换子类,其基本实现过程如下: (1)客户端针对抽象层编程,客户端代码中不能出现任何具体类类名,即客户端不直接实例化对象; (2)引入纯文本格式的配置文件,通常是XML文件,将具体类类名存储在配置文件中; (3)通过DOM(Document Object Model,文档对象模型)、SAX(Simple API for XML)等XML解析技术获取存储在配置文件中的类名; (4)在客户端代码中通过反射(Reflection)机制根据类名创建对象,用反射所创建的对象替换父类对象的引用,程序运行时,将调用子类方法来实现业务功能; (5)如果需要扩展功能,只需增加一个新的子类继承抽象父类,再修改配置文件,重新运行程序即可;如果需要替换功能,只需用另一个子类类名替换存储在配置文件中的原有子类类名即可。无论是扩展还是替换都无须修改既有类库和客户端源代码,完全符合开闭原则。

新建一个对象来获取配置属性:

 package com.atomview.signalgateway.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
* Created on 2018/10/9.
*/

public class StreamServerProperties {

@Value("#{propertiesReader['state']}")
private String m_ConnectState;

@Value("#{propertiesReader['server.ip']}")
private String m_StreamserverIp;

@Value("#{propertiesReader['server.port']}")
private String m_StreamserverPort;

public String getConnectState() {
return m_ConnectState;
}

public String getStreamserverIp() {
return m_StreamserverIp;
}

public String getStreamserverPort() {
return m_StreamserverPort;
}
}

这里面定义了5个IImageSelect接口的子类,通过定义好的泛型ImageSelectClientMode来决定实例化哪个子类,现在遇到这么一个问题,如果添加到第6个子类的话,那就必须要更改ImageSelectFactory类以及枚举ImageSelectClientMode,虽不说影响不影响什么开闭设计原则,但是有个情况你可成想到,你这个类要打包发布给别人的话,别人在没有源码的情况下如何扩展呢?这里就需要我们动态的通过配置文件来加载实现类了。

**通过读取本地的.properties文件来获取我们需要实例化的类,然后通过反射来生成对象,**这样当你把发布出去的时候,使用者只用更改配置文件就可以让工厂去实例化自己后来才写的实现类,我们看看实现方式: 通过读取本地的.properties文件来获取我们需要实例化的类,然后通过反射来生成对象,这样当你把发布出去的时候,使用者只用更改配置文件就可以让工厂去实例化自己后来才写的实现类,我们看看实现方式:

 public static class ImageSelectFactory {
        public static IImageSelect createIImageSelect(String type) {
            IImageSelect mIImageSelect;

            //实例化Properties对象,用于读取.properties
            Properties properties = new Properties();
            InputStream is = null;
            try {
                is = ImageSelectClient.class.getResourceAsStream("ImageSelectClient.properties");
                //装载ImageSelectClient.properties文件
                properties.load(is);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            try {
                //根据key获取value,value即为将要实例化的类
                Class<?> aClass = Class.forName(properties.getProperty(type));
                //使用反射进行实例化
                mIImageSelect = (IImageSelect) aClass.newInstance();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return mIImageSelect;
        }

我们就可以随便实现子类,然后在.properties文件中添加对应的包路径,然后通过ImageSelectFactory就可以进行实例化了。