定义一个用于创建对象的接口, 让子类决定实例化哪一个类。 工厂方法使一个类的实例化延迟到其子类。
角色:
Product 抽象产品,负责定义产品的共性,实现对事物抽象的定义
Creator 抽象创建类,也就是抽象工厂,具体如何创建产品类是由具体的实现工厂完成
ConcreteCreator 具体实现工厂
总结一下模板代码:
/**
* 产品抽象
*/
public interface Product {
void method();
}
/**
* 具体产品
*/
public class ConcreteProduct1 implements Product {
@Override
public void method() {
//具体产品方法
}
}
/**
* 抽象工厂类
*
*/
public interface Creator {
/*
* 创建一个产品对象, 其输入参数类型可以自行设置
* 通常为String、 Enum、 Class等, 当然也可以为空。
*/
<T extends Product> T createProduct(Class<T> c);
}
/**
* 抽象工厂实现
*/
public class ConcreteCreator implements Creator {
@Override
public <T extends Product> T createProduct(Class<T> c) {
Product product=null;
try {
product = (Product)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
//异常处理
}
return (T)product;
}
}
//测试代码:
public static void main(String[] args) {
//这时要new,也可以是个静态方法。这样抽象工厂就是一个工厂类了
Creator creator = new ConcreteCreator();
ConcreteProduct1 noticeProduct = creator.createProduct(ConcreteProduct1.class);
noticeProduct.method();
}
实际中往里面套就可以了,产品也可能是抽象类,也可能是一个具体的类(万物皆对象嘛)等等可以根据自己的需要修改。
优点:
上层不用关心具体的产品是怎么实现的,只要知道用那一种产品就行。
调用者不需要知道产品如何实现。
有新的产品了,只要产品接口不变,那么所有的上层调用都不用变。唯一要变的可能就是具体工厂的实现(模板代码中,都不需要修改)。
工厂方法模式的扩展:
1、 模板代码中。只需要一个工厂 ConcreteCreator 实例,所以就没有必要把它new出来,创建对象方法使用静态方法就可以。
2、每一个产品有一个产品工厂。适用于产品比较多,每个产品的初始化方法都不相同(不仅仅是new),如果写在一个产品工厂中那么此工厂可能会比较大(方法代码多)。为了结构清晰,为每一个产品创建一个工厂类,让调用者自己去选择使用那一个工厂。
3、替代单例模式。示例代码:
/**
* 单例
**/
public class Singleton {
//不允许通过new产生一个对象
private Singleton() {}
public void doSomething() {
//业务处理
}
}
/**
* 单例工厂
**/
public class SingletonFactory {
private static Singleton singleton;
//使用静态块来创建单例对象
static {
try {
Class cl = Class.forName(Singleton.class.getName());
//获得无参构造
Constructor constructor = cl.getDeclaredConstructor();
//设置无参构造是可访问的
constructor.setAccessible(true);
//产生一个实例对象
singleton = (Singleton) constructor.newInstance();
} catch (Exception e) {
//异常处理
}
}
public static Singleton getSingleton() {
return singleton;
}
}
4、延迟初始化。一个对象被消费完毕后, 并不立刻释放, 工厂类保持其初始状态, 等待再次被使用。 延迟初始化是工厂方法模式的一个扩展应用。
示例代码(工厂方法改写):
//容纳已经创建的对象
private static Map<Class,Product> map = new HashMap<>(16);
//工厂方法
public static synchronized <T extends Product> T create(Class<T> c) {
Product product=null;
if(map.containsKey(c)){
//如果map 中已存在创建的对象直接返回
return (T)map.get(c);
}
try {
product = (Product)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
//异常处理
}
return (T)product;
}
上面都是模板代码,一切皆可扩展。工厂方法模式在项目中用的比较多,多思考如何使用,而且很容易与其它模式混合使用。
抽象工厂模式
工厂方法模式就是单独生产某一个单独具体的产品,产品之间联系。在实际的工厂中,分为很多车间,每个车间又分为多个生产线,分别生产不同的产品,生产完毕就可以在系统外组装,各个车间和生产线的职责非常明确,在车间内各个生产出来的产品可以有耦合关系,生产的时候在一个车间内协调好。这就是抽象工厂模式。
定义:
为创建一组相关或相互依赖的对象提供一个接口, 而且无须指定它们的具体类。
抽象工厂模式是工厂方法模式的升级版本, 在有多个业务品种、 业务分类时, 通过抽象工厂模式产生需要的对象是一种非常好的解决方式。 比如:生产车辆的左侧车门和右侧车门,这两个应该是数量相等的(产品之间的约束),叫做产品族。每种车型车门都是不一样的,这是产品等级结构约束。
示例:生产车门,一辆车有左侧门和右门。UML 图如下:
注:左侧门和右侧门是两个产品族, LeftDoor BenzLeftDoor BMWLeftDoor 为同一个产品等级,RightDoor BenzRightDoor BMWRightDoor 为同一个产品等级。
代码:
Door类及其子类
/**
* 车门抽象类
*/
public abstract class Door {
public void open(){
System.out.println("open door");
}
public void close(){
System.out.println("close door");
}
/**
* 车门类型,左侧门还是右侧门
*/
public abstract void type();
/**
* 子类实现
*/
public abstract void other();
}
/**
* 左侧门
*/
public abstract class LeftDoor extends Door{
@Override
public void type() {
System.out.println("这是左侧门");
}
}
/**
* 右侧门
*/
public abstract class RightDoor extends Door{
@Override
public void type() {
System.out.println("这是右侧门");
}
}
/**
* Benz 左侧门
*/
public class BenzLeftDoor extends LeftDoor {
@Override
public void other() {
System.out.println("BenzLeftDoor");
}
}
/**
* Benz 左侧门
*/
public class BenzRightDoor extends RightDoor {
@Override
public void other() {
System.out.println("BenzRightDoor");
}
}
/**
* BMW 车辆左侧门
*/
public class BMWLeftDoor extends LeftDoor {
@Override
public void other() {
System.out.println("BMWLeftDoor 改成黑色");
}
}
/**
* BMW 车辆右侧门
*/
public class BMWRightDoor extends RightDoor {
@Override
public void other() {
System.out.println("BMWLeftDoor 改成白色");
}
}
工厂类
/**
* 抽象车门创建者
*/
public abstract class AbstractDoorCreator {
/**
* 生产左侧门
* @return
*/
public abstract LeftDoor createLeftDoor();
/**
* 生产右侧门
* @return
*/
public abstract RightDoor createRightDoor();
}
/**
* bmw 车门创建者
*/
public class BMWDoorCreator extends AbstractDoorCreator {
@Override
public LeftDoor createLeftDoor() {
return new BMWLeftDoor();
}
@Override
public RightDoor createRightDoor() {
return new BMWRightDoor();
}
}
/**
* benz 车门创建者
*/
public class BenzDoorCreator extends AbstractDoorCreator {
@Override
public LeftDoor createLeftDoor() {
return new BenzLeftDoor();
}
@Override
public RightDoor createRightDoor() {
return new BenzRightDoor();
}
}
测试代码:
public static void main(String[] args) {
//创建 BenzDoorCreator 工厂,生产 benz 的车门
BenzDoorCreator benzDoorCreator = new BenzDoorCreator();
LeftDoor benzLeftDoor = benzDoorCreator.createLeftDoor();
RightDoor benzRightDoor = benzDoorCreator.createRightDoor();
//创建 BMWDoorCreator 工厂,生产BWM 的车门
BMWDoorCreator bmwDoorCreator = new BMWDoorCreator();
LeftDoor bmwLeftDoor = bmwDoorCreator.createLeftDoor();
RightDoor bmwRightDoor = bmwDoorCreator.createRightDoor();
//生产完毕,可以在这里做想做的事情
}
优点:
封装性,调用者只要关心接口(抽象类)就行,只要知道具体的工厂,就能生产出想要的产品。
产品内部的约束不公开,由工厂内部实现比如生产一个左侧门就要对应一个右侧门。
缺点:
产品族扩展困难,比如要加一个天窗门,那么修改的类就多了,工厂接口都需要修改。比如:新增了一个天窗的门,那么 AbstractDoorCreator 抽象类就要加一个生产天窗门的方法,整个代码都需要修改。
注意是产品族扩展困难不是产品等级,增加一个产品等级只要新增一个产品工厂就可以了。比如新增了一个大众的车门,那么新增一个大众的车门工厂就行。
使用场景:
一个对象族(或者一组没有关系的对象),都有相同的约束条件。如:一个文本编辑器和一个图片编辑器,两者没有关系,但是都要在windows系统和linux系统上使用,那么它们就有了同一个约束条件:操作系统。所以就可能使用抽象工厂模式,生产不同操作系统下的编辑器和图片处理器。
注:以上为模板代码,按照自己的项目可以修改。比如:车门工厂定义为 生产左侧门工厂和右侧门工厂,然后工厂类就是专用生产左侧门和右侧门的工厂类。