1. 抽象工厂模式
抽象工厂模式的原始定义是:提供了一个用于创建相关或相关对象族的接口,而无须指定其具体类
当我们在创建抽象工厂模式时,最终还是会涉及指定具体的实现类。换句话说,定义只是说了抽象工厂模式应该要朝着分析共性规律的方向走,而具体操作时我们还得仔细分析具体实现类该怎么实现才行
只有找到了正确的抽象产品,才能发挥抽象工厂模式的作用
UML图
从这个 UML 图中,我们能看出抽象工厂模式中其实包含了四个关键角色。
- 抽象工厂
- 抽象产品(通用的一类对象或接口)
- 具体工厂
- 具体产品(继承通用对象或接口后扩展特有属性)
/**
* @Description 抽象的家具工厂
*/
public abstract class AbsractFactory {
abstract Chair createChair();
abstract Sofa createSofa();
abstract Table createTable();
}
// 具体的工厂1
public class ChinaFactory extends AbsractFactory {
@Override
Chair createChair() {
return new ChinaChair();
}
@Override
Sofa createSofa() {
return new ChinaSofa();
}
@Override
Table createTable() {
return new ChinaTable();
}
}
// 具体的工厂2
public class USAFactory extends AbsractFactory{
@Override
Chair createChair() {
return new USAChair();
}
@Override
Sofa createSofa() {
return new USASofa();
}
@Override
Table createTable() {
return new USATable();
}
}
在实际的代码实现中,抽象工厂模式体现为定义一个抽象工厂类,多个不同的具体工厂继承这个抽象工厂类后,再各自实现相同的抽象功能,进而实现代码上的多态性
使用抽象工厂模式原因:
- 对于不同产品系列有比较多共性特征时,可以使用抽象工厂模式,有助于提升组件的复用性
- 当需要提升代码的扩展性并降低维护成本时,把对象的创建和使用过程分开,能有效地将代码统一到一个级别上
- 解决跨平台带来的兼容性问题
示例1
/**
* @Description 抽象工厂类
*/
public interface AbstractFactory {
Pizza createPizza(String orderType);
}
/**
* @Description 具体工厂1
*/
public class BJFactory implements AbstractFactory {
@Override
public Pizza createPizza(String orderType) {
System.out.println("抽象工厂模式......");
if ("cheese".equals(orderType)) {
return new BJCheesePizza();
} else if ("pepper".equals(orderType)) {
return new BJPepperPizza();
}
return null;
}
}
/**
* @Description 具体工厂2
*/
public class LDFactory implements AbstractFactory{
@Override
public Pizza createPizza(String orderType) {
System.out.println("抽象工厂模式......");
if ("cheese".equals(orderType)){
return new LDCheesePizza();
} else if ("pepper".equals(orderType)){
return new LDPepperPizza();
}
return null;
}
}
/**
* @Description 抽象产品
*/
public abstract class Pizza {
protected String name;
/**
* 准备原材料
*/
public abstract void prepare();
public void bake() {
System.out.println(name + " baking.");
}
public void cut() {
System.out.println(name + " cutting.");
}
public void box() {
System.out.println(name + " boxting.");
}
public void setName(String name) {
this.name = name;
}
}
/**
* @Description 产品1
*/
public class BJCheesePizza extends Pizza {
@Override
public void prepare() {
setName("北京奶酪披萨");
System.out.println(" 北京奶酪披萨准备原材料");
}
}
/**
* @Description 产品2
*/
public class LDCheesePizza extends Pizza {
@Override
public void prepare() {
setName("伦敦奶酪披萨");
System.out.println(" 伦敦奶酪披萨准备原材料");
}
}
/**
* @Description 产品3
*/
public class BJPepperPizza extends Pizza {
@Override
public void prepare() {
setName("北京胡椒披萨");
System.out.println(" 北京胡椒披萨准备原材料");
}
}
/**
* @Description 产品4
*/
public class LDPepperPizza extends Pizza {
@Override
public void prepare() {
setName("伦敦胡椒披萨");
System.out.println(" 伦敦胡椒披萨准备原材料");
}
}
/**
* @Description 测试代码
*/
public class OrderPizza {
AbstractFactory factory;
public OrderPizza(AbstractFactory factory){
this.factory = factory;
Pizza pizza = null;
String orderType;
do {
orderType = getType();
pizza = this.factory.createPizza(orderType);
if (null == pizza){
System.out.println("没有这种pizza..");
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while (true);
}
private String getType() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 各类: ");
return reader.readLine();
} catch (IOException ex) {
return "";
}
}
public static void main(String[] args) {
// new OrderPizza(new BJFactory());
new OrderPizza(new LDFactory());
}
}
2. 工厂方法模式
工厂方法模式因为只围绕着一类接口来进行对象的创建与使用,使用场景更简单和单一,在实际的项目中使用频率反而比抽象工厂模式更高
工厂方法模式的原始定义是:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。
工厂方法模式的目的很简单,就是封装对象创建的过程,提升创建对象方法的可复用性
为什么要用工厂方法模式?
- 为了把对象的创建和使用过程分开,降低代码耦合性
- 减少重复代码
- 统一管理创建对象的不同实现逻辑
UML图
工厂方法模式包含三个关键角色:
- 抽象接口(也叫抽象产品)
- 核心工厂
- 具体产品(也可以是具体工厂)
核心工厂通常作为父类负责定义创建对象的抽象接口以及使用哪些具体产品,具体产品可以是一个具体的类,也可以是一个具体工厂类,负责生成具体的对象实例。于是,工厂方法模式便将对象的实例化操作延迟到了具体产品子类中去完成。
不同于抽象工厂模式,工厂方法模式侧重于直接对具体产品的实现进行封装和调用,通过统一的接口定义来约束程序的对外行为。换句话说,用户通过使用核心工厂来获得具体实例对象,再通过对象的统一接口来使用对象功能
/**
* @Description 抽象产品
*/
public interface IProduct {
void apply();
}
//具体产品实现A
public class Product_A_Impl implements IProduct{
@Override
public void apply() {
System.out.println("use A product now");
}
}
//具体产品实现B
public class Product_B_Impl implements IProduct{
@Override
public void apply() {
System.out.println("use B product now");
}
}
/**
* @Description 核心工厂类
*/
public class ProductFactory {
public static IProduct getProuct(String name){
if ("a".equalsIgnoreCase(name)){
return new ProductA();
}
return new ProductB();
}
}
/**
* @Description 测试用例
*/
public static void main(String[] args) {
IProduct iProduct = ProductFactory.getProduct(""); // 核心工厂来获得具体实例对象
iProduct.apply();
IProduct iProducta = ProductFactory.getProduct("a"); // 通过对象的统一接口来使用对象功能
iProducta.apply();
}
在工厂方法模式中,核心的工厂 ProductFactory 类不会负责所有产品的创建,只是负责实现通用逻辑,具体的实例创建工作都是交给具体工厂去做的,同时子类需要实现一个公共的接口来对外提供统一的功能,这使得工厂方法模式可以允许程序在不修改工厂角色的情况下引入新的产品实现
工厂方法模式是围绕着特定的抽象产品(一般是接口)来封装对象的创建过程,客户端只需要通过工厂类来创建对象并使用特定接口的功能
使用场景分析
一般情况下,工厂方法模式有以下几个使用场景。
- 需要使用很多重复代码创建对象时,比如,DAO 层的数据对象、API 层的 VO 对象等。
- 创建对象要访问外部信息或资源时,比如,读取数据库字段,获取访问授权 token 信息,配置文件等。
- 创建需要统一管理生命周期的对象时,比如,会话信息、用户网页浏览轨迹对象等。
- 创建池化对象时,比如,连接池对象、线程池对象、日志对象等。这些对象的特性是:有限、可重用,使用工厂方法模式可以有效节约资源。
- 希望隐藏对象的真实类型时,比如,不希望使用者知道对象的真实构造函数参数等