Java设计模式:工厂模式

Java设计模式:工厂模式

    【尊重原创,转载请注明出处】http://blog.csdn.net/guyuealian/article/details/52015589
     工厂模式的意图:定义一个接口来创建对象,但是让子类来决定哪些类需要被实例化。工厂方法把实例化的工作推迟到子类中去是实现。 工厂模式可以 根据客户的需要, 定义一个工厂类专门负责创建类的实例。
一、先来看一下普通的设计模式:
public interface FruitInterface{
	public void Colour();
}
public class Apple implements FruitInterface{
	@Override
	public void Colour() {
		System.out.println("---苹果的颜色是红色的---");
	}
}
public class Orange implements FruitInterface{
	@Override
	public 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.Apple
Orange=com.fruit.Orange
Grape=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值告诉客户端使用者即可。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI吃大瓜

尊重原创,感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值