工厂方法模式是经常使用的一种设模式,基本可以分为产品,工厂和使用者。定义一个用于创建对象的接口,它的子类决定实现实例化哪一个类。最基本的工厂方法模式:包括一个抽象工厂类,定义工厂;工厂类实现工厂生产的具体细节;产品的抽象类,定义产品的属性和行为,实际的产品类,最终生产的产品。
举个例子,现在某地方需要新建一个工厂用来生产汽车,汽车的产品不限,包括:奔驰、路虎等等。首先新建的工厂前,首先拟定工厂的方案,一个抽象类AbstrcatCarFactory ;开始新建工厂CarFactory ;工厂建好了,需要设计产品Car ;更加不同的产品,细化产品细节LandOver 、Benz ;万事具备后只剩生产,建一个Woker 类。最终一辆辆成品汽车送去汽车试验场开始试验检测性能等品质。
/**
* 汽车工厂的抽象类
*/
public abstract class AbstrcatCarFactory {
public abstract T createCar(Class c);
}
/**
*汽车工产
*/
public class CarFactory extends AbstrcatCarFactory{
//生产汽车
@Override
public T createCar(Class c) {
Car car = null;
try {
car =(T)Class.forName(c.getName()).newInstance();
} catch (IllegalAccessException e) {
} catch (ClassNotFoundException e) {
} catch (InstantiationException e) {
}
return (T) car;
}
}
/**
* 汽车接口
*/
public interface Car {
void travel();
}
/**
* 奔驰
*/
public class Benz implements Car{
@Override
public void travel() {
System.out.println("奔驰可以去验车了");
}
}
/**
* 路虎
*/
public class LandOver implements Car{
@Override
public void travel() {
System.out.println("路虎可以去验车了");
}
}
public class Woker {
public static void main(String[] args) {
//汽车工厂
AbstrcatCarFactory carFactory = new CarFactory();
//生产奔驰车
Benz benz = carFactory.createCar(Benz.class);
benz.travel();
//生产路虎
LandOver landOver = carFactory.createCar(LandOver.class);
landOver.travel();
}
}
执行结果:
奔驰可以去验车了
路虎可以去验车了
从上面的示例代码中,可以看出工厂方法模式,具有良好的封装性;产品通过工厂来生产,产品的实例化都工厂类负责,调用者无序考虑其他因素,降低了产品和工人两个模块间的耦合度,而且屏蔽了产品的细节;同时,工厂类通过泛型限制了产品类型,只能是汽车;易于扩展,如果新增了一个产品类型,只需要实现了产品的抽象接口,如果工厂不满足产品的生产需求,需要对工厂进行改造,这些对于调用者来说是影响很低。
工厂方法模式,符合迪米特法则,调用者只需要知道产品的抽象类,不需了解具体的实现类;同时也符合依赖倒置原则,工厂定义方法参数产品的抽象类;同时也符合里氏替换原则,定义的是抽象类,实际传入的实现类。
工厂方法模式只是提供了一个规范,通过不同的场景,可以延申的范围更广,比如在实际项目中,并不需要新建工厂,只需要使工厂的静态方法,这种引申称之为简单工厂模式,只需要将上述的代码简单修改,去掉抽象工厂类,将工厂类生产产品的方法修改为静态方法:
/**
* 汽车工厂
*/
public class CarFactory{
//生产汽车
public static T createCar(Class c) {
Car car = null;
try {
car =(T)Class.forName(c.getName()).newInstance();
} catch (IllegalAccessException e) {
} catch (ClassNotFoundException e) {
} catch (InstantiationException e) {
}
return (T) car;
}
}
public class Woker {
public static void main(String[] args) {
//生产奔驰车
Benz benz = CarFactory.createCar(Benz.class);
benz.travel();
//生产路虎
LandOver landOver = CarFactory.createCar(LandOver.class);
landOver.travel();
}
}
如此修改代码变得更加简洁,所以称之为简单工厂模式,也被称为静态工厂模式,不过调整后的代码扩展性下降,不符合开闭原则,但是并没有影响者其使用。
实际项目中,一个工产可能并不满足需求,还可以根据产品的不同,可能不同的产品初始化的参数不同。这时候就可以根据不同的产品新建不同的工厂。这样一来的话也同样存在不容易扩展的问题,每新增一个产品就要新增一个工厂。当然还是根据场景需求来适度使用。在复杂的应用中采用多工厂的方法,增加一个协调类,避免调用者与各个子工厂交流,协调类的作用是封装子工厂类,对高层模块提供统一的访问接口。
单例模式生成的对象是固定的,如果一个项目中需要生成多个不同的单例,那岂不是要实现多个单例。那如果用工厂方法模式就解决现在的问题。通过静态代码块来加载生成单例,通过返回和类构造器生成单例对象,提供一个静态方法getSingleten()获取单例对象。
/**
* 单例工厂
*/
public class SingleFactory {
//单例对象
private static Singleton singleton;
static {
try {
Class> c = Class.forName(Singleton.class.getName());
//获取无参构造
Constructor> constructor = c.getDeclaredConstructor();
//设置无参构造是可以访问的
constructor.setAccessible(true);
//产生一个示例对象
singleton = (Singleton) constructor.newInstance();
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
} catch (NoSuchMethodException e) {
} catch (ClassNotFoundException e) {
}
}
//获取单例
public static Singleton getSingleten(){
return singleton;
}
}
对象在被使用后,并不想他立即释放,保证其初始化状态,等待下次使用。可以新建一个容器Map用来存放对象,key是对象的类型,value为实例对象。首先先判断实现对象是否在容器中,如果存在则直接返回, 不存在则重新实例化对象。
/**
* 延迟初始化
*/
public class ProductFactory {
//实例容器
private static final Map map = new HashMap<>();
public static synchronized Product createProduct(String type){
Product product = null;
if(map.containsKey(type)){
product = map.get(type);
}else{
if(type.equals("Product1")){
product = new ConcreteProduct1();
}else {
product = new ConcreteProduct2();
}
}
return product;
}
}
工厂方法模式,具有封装性好,易扩展,松耦合的特点。在实际项目中,还可以通过配置文件的形式来设定产品类和工厂类型。这样操作就具有灵活性。
参考《设计模式之禅》秦小波著