工厂模式:
概念:1、实例化对象,用工厂方法代替new操作
2、工厂模式包括工厂方法模式和抽象工厂模式
3、抽象工厂模式是工厂方法模式的扩展
意图:
定义一个接口来创建对象,但是让子类来决定哪些类需要被实例化
工厂方法把实例化的工作推迟到子类中去实现
场景:
1、有一组类似的对象需要创建
2、在编码时不能预见需要创建哪种类的实例
3、系统需要考虑扩展性,不应依赖于产品类实例如何被创建、
组合和表达的细节(低耦合,这个对象的变化尽量不影响到别的对象发生变化)
设计:
1、尽量松耦合,一个对象的依赖对象的变化与本身无关
2、具体产品与客户端剥离,责任分割
抽象工厂模式:系列、家族
生产一个产品:工厂
生产多个产品:抽象工厂
以脸萌为例:(正常实现)
1> HairInterface.javapackage 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