1. 初衷
写这篇文章的初衷,介绍一下工厂形式,以及详细运用实例。
2. 简略介绍
首要清晰一点就是工厂是用来干啥的,工厂是用来创立目标的。
工厂形式的作用
- 封装目标的创立进程: 工厂形式将目标的创立进程封装在工厂类中,使客户端代码不需求了解详细的构建进程,只需向工厂恳求目标即可。
- 进步代码的可保护性: 工厂形式能够会集办理目标的创立,假如需求修正目标的构建方式,只需修正工厂类而不影响客户端代码。
- 进步代码的扩展性: 工厂形式答应增加新的产品类型而无需修正现有客户端代码。这样能够方便地扩展应用程序。
- 下降耦合度: 运用工厂形式能够下降客户端代码与详细产品类之间的耦合度,因为客户端只与工厂接口交互,不需求直接与产品类交互。
- 进步代码的重用性: 工厂形式能够在不同的地方运用相同的工厂来创立目标,进步了代码的重用性。
3. 简略工厂形式
3.1 恳求快递实例,无设计形式情况
公共快递下单接口
public interface IExpressDelivery {
/**
* 快递下单
*/
OrderResponse createOrder(OrderRequest orderRequest);
}
京东快递下单
public class JDExpressDelivery implements IExpressDelivery{
@Override
public OrderResponse createOrder(OrderRequest orderRequest) {
// 省掉恳求京东的下单api进程
OrderResponse orderResponse = new OrderResponse();
orderResponse.setBillNo("京东快递单号");
return orderResponse;
}
}
顺丰快递下单
public class SFExpressDelivery implements IExpressDelivery {
@Override
public OrderResponse createOrder(OrderRequest orderRequest) {
// 省掉恳求顺丰的下单api进程
OrderResponse orderResponse = new OrderResponse();
orderResponse.setBillNo("顺丰快递单号");
return orderResponse;
}
}
圆通快递下单
public class YTExpressDelivery implements IExpressDelivery {
@Override
public OrderResponse createOrder(OrderRequest orderRequest) {
// 省掉恳求圆通的下单api进程
OrderResponse orderResponse = new OrderResponse();
orderResponse.setBillNo("圆通快递单号");
return orderResponse;
}
}
客户端调用
public class Test {
public static void main(String[] args) {
String type = "SF";
OrderResponse orderResponse = createOrderByType(type);
System.out.println("快递单号为"+orderResponse.getBillNo());
}
public static OrderResponse createOrderByType(String type) {
IExpressDelivery expressDelivery = null;
if (type.equals("JD")) {
expressDelivery = new JDExpressDelivery();
} else if (type.equals("SF")) {
expressDelivery = new SFExpressDelivery();
} else {
expressDelivery = new YTExpressDelivery();
}
OrderRequest orderRequest = new OrderRequest();
return expressDelivery.createOrder(orderRequest);
}
}
从客户端调用就能够看出客户端是需求依赖完成类的,当时举的例子实例化还是很简略的,假如实例化需求更杂乱的代码客户端的代码也会看起来很臃肿。
3.2 恳求快递实例,运用简略工厂形式
工厂
public class ExpressDeliveryFactory {
public static IExpressDelivery create(String deliveryType) {
IExpressDelivery expressDelivery = null;
if (deliveryType.equals("JD")) {
expressDelivery = new JDExpressDelivery();
} else if (deliveryType.equals("SF")) {
expressDelivery = new SFExpressDelivery();
} else {
expressDelivery = new YTExpressDelivery();
}
return expressDelivery;
}
}
客户端
public static void main(String[] args) {
String type = "SF";
OrderResponse orderResponse = createOrderByType(type);
System.out.println("快递单号为"+orderResponse.getBillNo());
}
public static OrderResponse createOrderByType(String type) {
IExpressDelivery expressDelivery = ExpressDeliveryFactory.create(type);
OrderRequest orderRequest = new OrderRequest();
return expressDelivery.createOrder(orderRequest);
}
3.3 简略工厂形式 + 反射优化
快递枚举类
@Getter
@AllArgsConstructor
public enum ExpressTypeEnum {
JD( "JD", "com.example.demo.express.JDExpressDelivery"),
SF("SF", "com.example.demo.express.SFExpressDelivery"),
YT("YT", "com.example.demo.express.YTExpressDelivery"),
;
private final String key;
private final String classPath;
}
优化后的工厂
public class ExpressDeliveryFactory {
public static IExpressDelivery create(ExpressTypeEnum expressTypeEnum) {
try {
Class<?> clazz = Class.forName(expressTypeEnum.getClassPath());
return (IExpressDelivery) clazz.getDeclaredConstructor().newInstance();
} catch (ClassNotFoundException | InvocationTargetException | InstantiationException | IllegalAccessException |
NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
客户端
public class Test {
public static void main(String[] args) {
OrderResponse orderResponse = createOrderByType(ExpressTypeEnum.SF);
System.out.println("快递单号为"+orderResponse.getBillNo());
}
public static OrderResponse createOrderByType(ExpressTypeEnum type) {
IExpressDelivery expressDelivery = ExpressDeliveryFactory.create(type);
OrderRequest orderRequest = new OrderRequest();
return expressDelivery.createOrder(orderRequest);
}
}
3.4 简略工厂形式的首要长处:
- 将目标的创立和详细产品的完成别离,下降了客户端代码与详细产品类的耦合度。
- 简化了客户端代码,客户端不需求了解目标的创立细节,只需调用工厂类的办法即可获得所需的目标。
- 能够轻松切换或替换详细产品类,不影响客户端的代码。
3.5 简略工厂形式一些局限性:
- 当需求增加新的产品类型时,需求修正工厂类的代码,违反了开闭准则。
- 工厂类可能会变得适当巨大,难以保护。
4. 工厂办法形式
4.1 恳求快递实例
将工厂创立产品的办法提出来创立一个笼统类,把原来的工厂变成笼统工厂
public interface IExpressFactory {
IExpressDelivery create();
}
创立多个工厂
京东快递的工厂
public class JDExpressFactory implements IExpressFactory{
@Override
public IExpressDelivery create() {
return new JDExpressDelivery();
}
}
顺丰快递的工厂
public class SFExpressFactory implements IExpressFactory {
@Override
public IExpressDelivery create() {
return new SFExpressDelivery();
}
}
圆通快递的工厂
public class YTExpressFactory implements IExpressFactory {
@Override
public IExpressDelivery create() {
return new YTExpressDelivery();
}
}
工厂类的简略工厂
先树立枚举类
@Getter
@AllArgsConstructor
public enum ExpressFactoryTypeEnum {
JD( "JD", "com.example.demo.express.JDExpressFactory"),
SF("SF", "com.example.demo.express.SFExpressFactory"),
YT("YT", "com.example.demo.express.YTExpressFactory"),
;
private final String key;
private final String classPath;
}
工厂的工厂
public class ExpressFactoryFactory {
public static IExpressFactory create(ExpressFactoryTypeEnum expressFactoryTypeEnum) {
try {
Class<?> clazz = Class.forName(expressFactoryTypeEnum.getClassPath());
return (IExpressFactory) clazz.getDeclaredConstructor().newInstance();
} catch (ClassNotFoundException | InvocationTargetException | InstantiationException | IllegalAccessException |
NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
最终在客户端调用
public class Test1 {
public static void main(String[] args) {
OrderResponse orderResponse = createOrderByType(ExpressFactoryTypeEnum.JD);
System.out.println("快递单号为"+orderResponse.getBillNo());
}
private static OrderResponse createOrderByType(ExpressFactoryTypeEnum typeEnum) {
IExpressFactory iExpressFactory = ExpressFactoryFactory.create(typeEnum);
IExpressDelivery expressDelivery = iExpressFactory.create();
OrderRequest orderRequest = new OrderRequest();
return expressDelivery.createOrder(orderRequest);
}
}
4.2 工厂办法形式总结
工厂办法形式是简略工厂形式的延伸,它继承了简略工厂形式的长处,一起还弥补了简略工厂形式的不足。工厂办法形式是运用频率最高的设计形式之一,是许多开源框架和API类库的中心形式。
4.3工厂办法形式的首要长处
- 在工厂办法形式中,工厂办法用来创立客户所需求的产品,一起还向客户躲藏了哪种详细产品类将被实例化这一细节,用户只需求关怀所需产品对应的工厂,无须关怀创立细节,甚至无须知道详细产品类的类名。
- 根据工厂人物和产品人物的多态性设计是工厂办法形式的要害。它能够让工厂能够自主确认创立何种产品目标,而如何创立这个目标的细节则彻底封装在详细工厂内部。工厂办法形式之所以又被称为多态工厂形式,就正是因为一切的详细工厂类都具有同一笼统父类。
- 运用工厂办法形式的另一个长处是在体系中加入新产品时,无须修正笼统工厂和笼统产品供给的接口,无须修正客户端,也无须修正其他的详细工厂和详细产品,而只要增加一个详细工厂和详细产品就能够了,这样,体系的可扩展性也就变得非常好,彻底符合”开闭准则”。
4.4 工厂办法形式的首要缺陷
- 在增加新产品时,需求编写新的详细产品类,而且还要供给与之对应的详细工厂类,体系中类的个数将成对增加,在一定程度上增加了体系的杂乱度,有更多的类需求编译和运行,会给体系带来一些额定的开销。
- 因为考虑到体系的可扩展性,需求引进笼统层,在客户端代码中均运用笼统层进行定义,增加了体系的笼统性和理解难度,且在完成时可能需求用到DOM、反射等技能,增加了体系的完成难度。
4.5 适用场景
- 客户端不知道它所需求的目标的类。在工厂办法形式中,客户端不需求知道详细产品类的类名,只需求知道所对应的工厂即可,详细的产品目标由详细工厂类创立,可将详细工厂类的类名存储在配置文件或数据库中。
- 笼统工厂类通过其子类来指定创立哪个目标。在工厂办法形式中,对于笼统工厂类只需求供给一个创立产品的接口,而由其子类来确认详细要创立的目标,利用面向目标的多态性和里氏代换准则,在程序运行时,子类目标将覆盖父类目标,从而使得体系更简单扩展。