Java设计模式:工厂模式

来源:互联网 发布:细菌觅食算法 编辑:程序博客网 时间:2024/06/07 17:17

Java设计模式:工厂模式

    【尊重原创,转载请注明出处】http://blog.csdn.net/guyuealian/article/details/52015589
     工厂模式的意图:定义一个接口来创建对象,但是让子类来决定哪些类需要被实例化。工厂方法把实例化的工作推迟到子类中去是实现。 工厂模式可以根据客户的需要,定义一个工厂类专门负责创建类的实例。
一、先来看一下普通的设计模式:
public interface FruitInterface{public void Colour();}public class Apple implements FruitInterface{@Overridepublic void Colour() {System.out.println("---苹果的颜色是红色的---");}}public class Orange implements FruitInterface{@Overridepublic void Colour() {System.out.println("---橘子的颜色是黄色的---");}}public class FruitTest { //客户端程序public static void main(String[] args) {FruitInterface f = new Apple();f.Colour();}       }
     上面的客户端程序Fruit f = new Apple();可以获得苹果的颜色,但若要获得橘子的颜色,就需要在客户端增加橘子的实例化代码,并显式的调用;这样并不利于后期的维护和管理;决解的方法是新建一个工厂,通过IF判断语句,根据客户端需要,实例化对应的对象,实现对颜色的统一管理

二、新增加一个Factory作为过渡端,并通过过渡端取得接口的实例化对象,这个过渡端就是工厂类:
//工厂类,用于生产对象public class Factory {public FruitInterface getColour(String key) {FruitInterface f = null;// 定义接口对象,通过过子类实例化if ("Apple".equals(key)) {f = new Apple();// 通过Apple类实例化接口} else if ("Orange".equals(key)) {f = new Orange();// 通过Orange类实例化接口}return f;}}
//客户端程序public class FruitTest {public static void main(String[] args) {//(1)普通设计模式,客户端需要显式的实现化对象        // FruitInterface f = new Apple();// f.Colour();        //(2)工厂设计模式,客户端仅需要改变输入参数,增加新类时需要修改工厂类Factory factory = new Factory();FruitInterface colour = factory.getColour("Apple");colour.Colour();}}
       与普通的设计模式相比,工厂模式实例过程是在工厂类完成的,而不是在客户端的代码中实现的,客户端只需改变输入参数(改变参数Apple),即可获得对用的实例对象。通过工厂类,可以避免客户端显式的调用颜色这个方法,从而降低了客户端程序与产品对象的耦合。

三、继续改进:工厂类中通过IF判断语句,可以选择性地创建需要的实例化对象;但这时,如果需要增加新的水果,如葡萄时;需要改动两个地方:不仅需要新建一个葡萄的类,还需要在工厂类中添加判断和实例化语句。为了降低程序的耦合,这时需要用到反射的机制来动态的创建对象。
      继续改进Factory类:

//工厂类,用生产对象public class Factory {// 根据类型来创建对象public FruitInterface getColour(String key) {FruitInterface f = null;// 定义接口对象,同过子类实例化if ("Apple".equals(key)) {f = new Apple();// 通过Apple类实例化接口} else if ("Orange".equals(key)) {f = new Orange();// 通过Orange类实例化接口}return f;}// 通过反射,根据类的名称来生产对象public FruitInterface getColourByClass(String className) throws Exception {FruitInterface fruit = (FruitInterface) Class.forName(className).newInstance();return fruit;}}
//客户端程序public class FruitTest {public static void main(String[] args) throws Exception {//(1)普通设计模式,客户端需要显式的实现化对象        // FruitInterface f = new Apple();// f.Colour();        //(2)工厂设计模式,客户端仅需要改变输入参数//Factory factory = new Factory();// FruitInterface colour = factory.getColour("Apple");// colour.Colour();        //(3)通过反射的工厂设计模式,客户端仅需要改变输入参数        Factory factory = new Factory();FruitInterface colour = factory.getColourByClass("com.fruit.Apple");colour.Colour();}}
      通过反射的工厂设计模式,当有新增加的类时,如增加葡萄这种水果,这时只需要新建一个子类Grape,并实现接口FruitInterface的方法Colour(),客户端仅需要改变输入参数(更改参数com.fruit.Apple即可),而Factory类不需要修改任何代码。
PS:通过反射的方式创建对象,性能会要稍微低些,通常情况下,没有必要使用反射来创建对象,只有当程序需要动态创建某个类的对象时才考虑使用反射。
四、升级改进:
      通过反射的工厂设计模式已经可以大大的降低程序的耦合,但这时客户端输入参数时,需要输入整个完整的全限定类名(即完整的包名+类名),如果需要多个实例对象,这时客户端需要进行多次的更改参数;解决的方法是,把需要配置的参数以键值对象(Key-Value)的形式保存在属性文件中。而客户端只需要知道Key值就可以调用。
      新建属性文件type.properties,其以key-value的形式保存输入参数和包名的对应关系
Apple=com.fruit.AppleOrange=com.fruit.OrangeGrape=com.fruit.Grape
     有了属性文件,就需要获取和解释该属性文件的类PropertiesReader 
//properties文件的读取工具public class PropertiesReader {public Map<String, String> getProperties() {Properties props = new Properties();Map<String, String> map = new HashMap<String, String>();try {InputStream in = getClass().getResourceAsStream("type.properties");props.load(in);Enumeration en = props.propertyNames();while (en.hasMoreElements()) {String key = (String) en.nextElement();String property = props.getProperty(key);map.put(key, property);// System.out.println(key + "  " + property);}} catch (Exception e) {e.printStackTrace();}return map;}}
      在工厂类Factory中,新增加一个方法getColourByClassKey,获取属性文件,并根据value值来生产对象:
//通过获取属性文件,根据value值来生产对象public FruitInterface getColourByClassKey(String key) throws Exception {Map<String, String> map = new PropertiesReader().getProperties();FruitInterface fruit = (FruitInterface) Class.forName(map.get(key)).newInstance();return fruit;}
     这时客户端只需要传入一个key值即可:
// (4)传入Key值,获取属性文件FruitInterface colour = factory.getColourByClassKey("Apple");colour.Colour();
     这种升级后的工厂设计模式,把需要的映射的关系都保存到属性文件中,客户端只需要知道属性文件中key值,就可以实现功能;维护时,只需要修改属性文件,把key值告诉客户端使用者即可。


0 0
原创粉丝点击