目录
前言
Java 设计模式中的工厂方法模式,如果你看过我之前写的简单工厂模式 会更容易理解下面的讲解,为了便于理解工厂方法模式我依然用食品加工厂为案例。
一. 概述
工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同 的工厂子类来分担。
工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“顶级类”。这样便分担了对象创建的压力;避免工厂类中用逻辑判断来决定创建对象, 而且这样使得结构变得相当灵活当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的规则来生成,那么就可以被客户使用,而不必去修改任何已有的 代码,可以看出工厂方法模式符合开闭原则。
二. 结构图
- AbstractProduct 类:抽象产品类,工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口
- Berr 类和 Drinks 类:具体产品类,是简单工厂模式的创建目标
- AbstractFactory 类:抽象工厂类,这是工厂方法模式的核心,是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现
- BerrFactory 类和 DrinksFactory 类:具体工厂类,它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象
三. 举例说明
这里我们以食品加工厂来举例,假设有一个食品加工厂,主要加工啤酒饮料矿泉水,根据需求,我们就需要用一个单独的类来专门生产啤酒饮料矿泉水,因为我们的工厂后期一定会做大做强,所以我们就要考虑这个设计方案对后续的业务拓展影响,我们厂子要求设计之初必须要在不影响现有业务基础上,能灵活拓展新的制造业务,根据食品加工厂的需求,我们采用了工厂方法设计模式。
四. 具体代码实现
第一步:设计我们产品也就是我们要生产的对象,按照结构我们设计代码如下
抽象产品类代码所有产品的父类,代码如下:
package pattern.factory.product;
/**
* 创建产品抽象类也可以用接口来定义
* @author ningbeibei
*
*/
public abstract class AbstractProduct {
//获取产品抽象方法,需要具体的实现类来实现
public abstract void getFood();
}
具体产品Berr(啤酒),代码如下:
package pattern.factory.product;
/**
* 啤酒具体啤酒类继承自AbstractProduct类
* @author ningbeibei
*/
public class Berr extends AbstractProduct {
@Override
public void getFood() {
System.out.println("啤酒");
};
}
具体产品Drinks (饮料),代码如下:
package pattern.factory.product;
/**
* 具体饮料类继承自AbstractProduct
* @author ningbeibei
*/
public class Drinks extends AbstractProduct {
@Override
public void getFood() {
System.out.println("饮料");
}
}
第二步:设计制造产品的工厂,这也是工厂方法模式最总要的环节
创建工厂抽象类,代码如下:
package pattern.factory.factorymill;
import pattern.factory.product.AbstractProduct;
/**
* 抽象工厂类,食品加工厂需要进行抽象设计
* @author ningbeibei
*
*/
public abstract class AbstractFactory {
//这个抽象方法返回一个产品对象,
public abstract AbstractProduct createProduct();
}
创建具体啤酒制造工厂类BerrFactory,代码如下:
package pattern.factory.factorymill;
import pattern.factory.product.AbstractProduct;
import pattern.factory.product.Berr;
/**
* 专门知道啤酒的工厂,这个类实现自 AbstractFactory抽象类
* 返回一个啤酒产品对象
* @author ningbeibei
*
*/
public class BerrFactory extends AbstractFactory {
//实现抽象工厂返回啤酒
@Override
public AbstractProduct createProduct() {
return new Berr();
}
}
创建具体饮料制造工厂类,代码如下:
package pattern.factory.factorymill;
import pattern.factory.product.AbstractProduct;
import pattern.factory.product.Drinks;
/**
* 专门制造饮料工厂,继承自AbstractFactory抽象类
* @author ningbeibei
*/
public class DrinksFactory extends AbstractFactory {
//返回饮料对象
@Override
public AbstractProduct createProduct() {
return new Drinks();
}
}
第三步:编写测试类进行测试验证
package pattern.factory;
import pattern.factory.factorymill.BerrFactory;
import pattern.factory.factorymill.DrinksFactory;
import pattern.factory.product.AbstractProduct;
/**
* 工厂方法模式测试类
* @author ningbeibei
*/
public class test {
public static void main(String[] args) {
//先创建啤酒工厂
BerrFactory berrfactory = new BerrFactory();
//调用啤酒工厂中createProduct()方法,创建啤酒对象并返回
AbstractProduct product = berrfactory.createProduct();
//输出啤酒
product.getFood();
//先创建饮料工厂
DrinksFactory drinksfactory = new DrinksFactory();
//调用饮料工厂中createProduct()方法,创建饮料对象并返回
AbstractProduct drinksproduct = drinksfactory.createProduct();
//输出饮料
drinksproduct.getFood();
}
}
测试结果:
五. 如何扩展新的产品
随着食品加工的规模扩张,我们食品加工厂想制造更多的产品,现在想制造矿泉水,根据设计之初的构想,不管后期业务扩展何种产品都不会动摇现有的代码,也就是不违背工厂模式的开闭原则。
1.新增产品矿泉水类并继承抽象产品类,代码如下:
package pattern.factory.product;
/**
* 新增矿泉水产品,同样继承自产品抽象类AbstractProduct
* @author ningbeibei
*
*/
public class Water extends AbstractProduct {
@Override
public void getFood() {
System.out.println("矿泉水");
}
}
2.新增具体制造矿泉水工厂类并继承抽象类AbstractFactory,代码如下:
package pattern.factory.factorymill;
import pattern.factory.product.AbstractProduct;
import pattern.factory.product.Water;
/**
* 新增矿泉水制造工厂
* 继承自AbstractFactory抽象类
* @author ningbeibei
*
*/
public class WaterFactory extends AbstractFactory{
//制造矿泉水对象并返回
@Override
public AbstractProduct createProduct() {
return new Water();
}
}
3.测试类编写,代码如下:
package pattern.factory;
import pattern.factory.factorymill.BerrFactory;
import pattern.factory.factorymill.DrinksFactory;
import pattern.factory.factorymill.WaterFactory;
import pattern.factory.product.AbstractProduct;
/**
* 工厂方法模式测试类
* @author ningbeibei
*/
public class test {
public static void main(String[] args) {
//先创建啤酒工厂
BerrFactory berrfactory = new BerrFactory();
//调用啤酒工厂中createProduct()方法,创建啤酒对象并返回
AbstractProduct product = berrfactory.createProduct();
//输出啤酒
product.getFood();
//先创建饮料工厂
DrinksFactory drinksfactory = new DrinksFactory();
//调用饮料工厂中createProduct()方法,创建饮料对象并返回
AbstractProduct drinksproduct = drinksfactory.createProduct();
//输出饮料
drinksproduct.getFood();
//这个是新增产品矿泉水
WaterFactory waterfactory = new WaterFactory();
//调用矿泉水工厂中createProduct()方法,创建矿泉水对象并返回
AbstractProduct waterproduct = waterfactory.createProduct();
//输出矿泉水
waterproduct.getFood();
}
}
4.测试结果:
六. 工厂方法模式优缺点
缺点:
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
- 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程
- 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类
- 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则