本文讨论一下一种名叫工厂模式的设计模式,首先先谈一些偏概念的东西:
工厂模式概念:
实例化对象,用工厂方法代替new操作
工厂模式包括工厂方法模式和抽象工厂模式
抽象工厂模式是工厂方法模式的拓展
工厂模式的意图:
定义一个接口来创建对象,但是让子类来决定哪些类需要被实例化
工厂方法把实例化的工作推迟到子类中去实现
适合工厂模式的情况:
有一组类似的对象需要创建
在编码时不能遇见需要创建哪种类的实例
系统需要考虑扩展性,不应依赖于产品实例如何被创建、组合和表达的细节
工厂模式的动机:
尽量松耦合,一个对象的依赖对象的变化和本身无关
具体产品和客户端剥离,责任分割
我们来看一下工厂方法模式:
我们先创建一个iCar接口 放在com.factory下:
package com.factory;
public interface iCar{
public void run();//iCar约定的方法
}
接下来用几种不同的车,分别是truck和sportscar,分别创建不同的类,实现iCar,放在com.factory下:
package com.factory;
public class Truck implements iCar{
public void run(){
System.out.println("I'm a truck");
}
}
package com.factory;
public class Sportscar implements iCar{
public void run(){
System.out.println("I'm a sportscar");
}
}
我们来尝试以下用带反射和类名映射的工厂方法模式创建这两种不同的车,创建一个CarFactory类,放在com.factory下:
package com.factory;
import java.util.Map;
public class CarFactory{
public iCar getCarByClassKey(String key){
try {
Map<String,String> map = new PropertiesReader().getProperties();//创建一个properties文件读取器 读取我们的key和完整类名的映射关系
iCar car = (iCar)Class.forName(map.get(key)).newInstance();//利用反射动态创建对应类名的对象
return car;
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
细心的同学也发现了,我们还需要写一个读取存储key和完整类名映射关系的properties文件的类,我们也放在com.factory下:
package com.factory;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class PropertiesReader {
/*
* 文件读取类 读取properties
* */
public Map<String,String> getProperties(){
Properties props = new Properties();
Map<String , String> map = new HashMap<String,String>();
try{
InputStream in =getClass().getResourceAsStream("type.properties");//读取当前路径下的type.properties文件
props.load(in);
Enumeration en = props.propertyNames();
while(en.hasMoreElements()){
String key = (String)en.nextElement();
String property = props.getProperty(key);//使用枚举循环读取properties文件
map.put(key, property);
}
return map;
}
catch( Exception e){
e.printStackTrace();
}
return null;
}
}
然后在当前文件路径创建type.properties,做key与类的映射:
truck=com.factory.Truck
sportscar=com.factory.Sportscar
最后就可以写一个测试类Test来进行测试了:
package com.factory;
public class Test{
public static void main(String[] args){
CarFactory fatory = new CarFactory();//创建一个造车工厂
iCar truck = factory.getCarByClassKey("truck");//读取对应的映射类 创建对应的对象
iCar sportscar = factory.getCarByClassKey("Sportscar");
truck.run();//I'm a truck
sportscar.run();//I'm a sportscar
}
}
有没有看出这样写的优势?我们可以将创建对象的过程交给一个工厂,实现类与类的松耦合;另一方面,如果我们想要在工厂里加入新的车种类,比如我们想加入SUV,只需要用SUV类实现iCar接口,然后在type.properties文件中写入key以及对应的类全称,就可以在工厂中创建一辆SUV,实现他该有的方法,这样的设计具有很好的可扩展性。