工厂模式之工厂方法模式

工厂模式:

 概念:
    1、实例化对象,用工厂方法代替new操作
    2、工厂模式包括工厂方法模式和抽象工厂模式
    3、抽象工厂模式是工厂方法模式的扩展

 意图:
    定义一个接口来创建对象,但是让子类来决定哪些类需要被实例化
    工厂方法把实例化的工作推迟到子类中去实现

 场景:
    1、有一组类似的对象需要创建
    2、在编码时不能预见需要创建哪种类的实例
    3、系统需要考虑扩展性,不应依赖于产品类实例如何被创建、
          组合和表达的细节(低耦合,这个对象的变化尽量不影响到别的对象发生变化)

 设计:
    1、尽量松耦合,一个对象的依赖对象的变化与本身无关
    2、具体产品与客户端剥离,责任分割

抽象工厂模式:系列、家族

     生产一个产品:工厂    
     生产多个产品:抽象工厂  

以脸萌为例:(正常实现)

1> HairInterface.java

package com.zy.factoryProject;


public interface HairInterface {

	// 生成发型
	public void draw();
}

2> leftHair.java

package com.zy.factoryProject;

public class leftHair implements HairInterface {

	/**
	 * 画一个左偏分发型
	 */
	@Override
	public void draw() {
		System.out.println("---左偏分发型---");
	}

}

3> rightHair.java

package com.zy.factoryProject;

public class rightHair implements HairInterface {

	/**
	 * 画一个右偏分发型
	 */
	@Override
	public void draw() {
		System.out.println("---右偏分发型---");
	}

}

4> Test.java

package com.zy.factoryProject;

public class Test {

	/**
	 * 模拟客户端
	 * @param args
	 */
	public static void main(String[] args) {
		HairInterface left = new leftHair();
		left.draw();
	}

}

*上述做法明显有缺陷,就是每次要创建一个新的发型都要建立新的xxxhair.java,并且都要在客户端显式的调用

为了解决上述问题:

1> 创建发型工厂,用于根据客户端需求创建发型:(HairFactory.java)

package com.zy.factoryProject;

/**
 * 发型工厂
 * 
 * @author Administrator
 * 
 */
public class HairFactory {

	/**
	 * 根据类型来创建对象
	 * 
	 * @param key
	 * @return
	 */
	public HairInterface getHair(String key) {
		// 这里把key放在equals里面,因为进来没对key进行是否为空的判断,这样可以避免抛空指针
		// 如果关键字是左偏分,则产生一个左偏分发型
		if ("left".equals(key)) {
			return new leftHair();
		} else if ("right".equals(key)) {
			return new rightHair();
		}
		return null;
	}

}

2> 客户端根据需求调用工厂进行发型的创建:(Test.java)

package com.zy.factoryProject;

public class Test {

	/**
	 * 模拟客户端
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		HairFactory factory = new HairFactory();
		HairInterface left = factory.getHair("left");
		left.draw();
	}

}

*但是反观上述HaorFactory工厂,每当要产生一个新发型都要if else判断,不能智能的创建

为了解决上述问题,应用类的反射,进行智能创建

1> 在HairFactory.java中添加方法:

	/**
	 * 根据类名来产生对象
	 * 
	 * @param className
	 * @return
	 */
	public HairInterface getHairByClass(String className) {

		try {
			HairInterface hair = (HairInterface)Class.forName(className)
					.newInstance();
			return hair;
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}

2> 在客户端调用:

		HairFactory factory = new HairFactory();
		HairInterface left = factory.getHairByClass("com.zy.factoryProject.leftHair");
		left.draw();

*上述这样实现的好处:增加一个发型时,只要增加这个发型的类,并告知客户端存在这个发型的类,通过工厂进行调用即可

*但是这样在客户端调用也不方便,类名太长(com.zy.factoryProject.leftHair),需要做映射


1> 创建type.properties文件进行映射信息的配置

left=com.zy.factoryProject.leftHair
right=com.zy.factoryProject.rightHair

2> 创建PropertiesReader对properties文件进行读取

package com.zy.factoryProject;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * properties文件读取工具
 * 
 * @author Administrator
 * 
 */
public class PropertiesReader {

	public Map<String, String> getProperties() {

		// 这里Properties对象导的包是java.util.Properties
		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);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}

}

3> HairFactory增加根据配置文件创建发型的方法:

	/**
	 * 根据配置文件来产生对象
	 * 
	 * @param className
	 * @return
	 */
	public HairInterface getHairByKey(String key) {

		try {
			// 类名从配置文件中读取
			Map<String, String> map = new PropertiesReader().getProperties();
			HairInterface hair = (HairInterface)Class.forName(map.get(key))
					.newInstance();
			return hair;
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}

4> 进行测试:

		HairFactory factory = new HairFactory();
		HairInterface hair = factory.getHairByKey("right");
		hair.draw();

*通过上述设置,这时,如果需要加入新的发型,则:

1> 创建对应新发型的类:(inHair.java中分发型)

package com.zy.factoryProject;

public class inHair implements HairInterface {

	@Override
	public void draw() {
		System.out.println("---中分发型---");
	}

}

2> 在配置文件中添加对应的映射:

in=com.zy.factoryProject.inHair

3> 告知客户端实现中分发型:

		HairInterface hair = factory.getHairByKey("in");
		hair.draw();

*如此一来,只需要新增对象时,只需要增加对象的实现方法和在配置文件中写好映射,并且告知客户端映射的key值即可,不需要改变factory


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值