简单工厂模式
工厂模式用于实现逻辑的封装,并通过公共的接口提供对象的实例化服务,在添加新的类时只需做少量的修改。
TeaFactory
类中包含 GreenTea
、RedTea
、GuanYinTea
的实例化方法 createTea()
,当客户需要对象时,调用 TeaFactory
的 createTea()
方法,并传所需的对象类型即可。TeaFactory
实例化相应的对象(如 GreenTea
)并返回,返回的对象被转换为基类类型。
静态工厂模式
新增工厂类 TeaFactory
,用于创建 Tea
实例。
- 创建抽象类
Tea
及继承它的三个具体类GreenTea
、RedTea
、GuanYinTea
;
public abstract class Tea {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
public void drink() {
System.out.println("喝茶......");
}
}
public class GreenTea extends Tea {
@Override
public void drink() {
System.out.println("喝绿茶");
}
}
public class RedTea extends Tea{
@Override
public void drink() {
System.out.println("喝红茶");
}
}
public class GuanYinTea extends Tea{
@Override
public void drink() {
System.out.println("喝铁观音");
}
}
- 创建工厂类;
public class TeaFactory {
public enum TeaTypeEnum {
/**
* 绿茶、红茶、铁观音
*/
GREEN_TEA,
RED_RED,
GUAN_YIN_TEA
}
public static Tea createTea(TeaTypeEnum type) {
switch (type) {
case GREEN_TEA:
return new GreenTea();
case RED_RED:
return new RedTea();
case GUAN_YIN_TEA:
return new GuanYinTea();
default:
return null;
}
}
public static void main(String[] args) {
// 测试
Tea tea = TeaFactory.createTea(TeaTypeEnum.RED_RED);
// 输出:喝红茶
tea.drink();
}
}
TeaFactory
只负责 Tea
类的实例化,符合单一职责原则;但是当我们需要新增一个新的 Tea
类时,需要修改 TeaFactory
的代码,这就有一定的局限性了。
我们可以改进这种简单工厂模式,使用注册的新类在使用时才被实例化,从而保证其对外扩展开放。
改进的简单工厂模式
- 在
Tea
类中新增抽象方法;
/**
* 用于返回实例
* @return
*/
abstract public Tea newInstance();
- 在其他三个具体类
GreenTea
、RedTea
、GuanYinTea
中实现抽象的方法,返回对应的实例;
public class GreenTea extends Tea {
@Override
public Tea newInstance() {
return new GreenTea();
}
@Override
public void drink() {
System.out.println("喝绿茶");
}
}
public class RedTea extends Tea{
@Override
public Tea newInstance() {
return new RedTea();
}
@Override
public void drink() {
System.out.println("喝红茶");
}
}
public class GuanYinTea extends Tea{
@Override
public Tea newInstance() {
return new GuanYinTea();
}
@Override
public void drink() {
System.out.println("喝铁观音");
}
}
- 在工厂类
TeaFactory
中,使用 Map 对象来保存具体类的标签和对应的类;
/**
* 使用 Map 对象来保存 Tea 和对应的类
*/
private static Map<String, Tea> registeredTeas = new HashMap<>();
- 新增方法
registerTea()
,用于添加新的Tea
类;
public static void registerTea(String teaTag, Tea tea) {
registeredTeas.put(teaTag, tea);
}
- 新增方法
getTea()
,用于获取对应的类;
public static Tea getTea(String teaTag) {
return registeredTeas.get(teaTag) == null ? null : registeredTeas.get(teaTag).newInstance();
}
- 测试
public static void main(String[] args) {
// 添加 GreenTea
TeaFactory.registerTea("green", new GreenTea());
TeaFactory.registerTea("red", new RedTea());
// 添加其他的 Tea 类......
Tea tea = TeaFactory.getTea("red");
if (null == tea) {
System.out.println("获取实例失败");
return;
}
// 输出:喝红茶
tea.drink();
}
工厂方法模式
工厂方法模式是在静态工厂模式上做的改进。工厂类被抽象化,用于实例化具体类的代码被转移到了子类。
在本例中,不同地区的茶叶工厂受制于环境等因素影响,杭州西湖一带生产的绿茶较好(仅举例说明),福建一带的产的红茶品质较好。为了效益和产品品质,商家决定在各个地区创办工厂,绿茶工厂仅能生产绿茶,红茶工厂仅能生产红茶。
本例工厂方法模式实现如下图所示:
AbstractTeaFactory
提供创建实例的方法,但不包含创建新实例的代码,拥有子类 GreenTeaFactory
及 RedTeaFactory
;GreenTeaFactory
用于生产绿茶,如 LongjingTea
(龙井)、MaojianTea
(毛尖);RedTeaFactory
用于生产红茶,如 JinjunmeiTea
(金骏眉)、BairuixiangTea
(百瑞香)。
- 新建
Tea2
类及其子类LongjingTea
、MaojianTea
、JinjunmeiTea
、BairuixiangTea
;
public abstract class Tea2 {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 新增抽象工厂类,请注意该工厂类不包含任何创建新实例的代码;
public abstract class AbstractTeaFactory {
/**
* 生产
* @param teaTag tag
* @return
*/
protected abstract Tea2 createTea(String teaTag);
public Tea2 setTeaName(String teaTag, String teaName) {
Tea2 tea = createTea(teaTag);
tea.setName(teaName);
return tea;
}
}
- 新增
AbstractTeaFactory
子类,如生产绿茶的工厂GreenTeaFactory
,重写父类的createTea()
方法,用于创建具体的实例;
public class GreenTeaFactory extends AbstractTeaFactory {
@Override
protected Tea2 createTea(String teaTag) {
if ("longjing".equals(teaTag)) {
return new LongjingTea();
} else if ("maojian".equals(teaTag)) {
return new MaojianTea();
} else {
return null;
}
}
}
在客户端,实例化工厂类并创建实例:
GreenTeaFactory teaFactory = new GreenTeaFactory();
teaFactory.setTeaName("longjing", "龙井");
- 同理,创建
RedTeaFactory
,用于生产红茶;
public class RedTeaFactory extends AbstractTeaFactory {
@Override
protected Tea2 createTea(String teaTag) {
if ("jinjunmei".equals(teaTag)) {
return new JinjunmeiTea();
} else if ("baituixiang".equals(teaTag)) {
return new BairuixiangTea();
} else {
return null;
}
}
}
在客户端,实例化工厂类并创建实例:
RedTeaFactory redTeaFactory = new RedTeaFactory();
redTeaFactory.setTeaName("jinjunmei", "金骏眉");
后来,市场上又流行了黑茶,商家决定迎合市场,进一步扩展业务,创建了黑茶工厂,用于生产黑茶类产品。因此我们建一个黑茶工厂 BlackTeaFactory
:
public class BlackTeaFactory extends AbstractTeaFactory{
@Override
protected Tea2 createTea(String teaTag) {
if ("puer".equals(teaTag)) {
return new PuerTea();
}
return null;
}
}
生产黑茶类产品:
BlackTeaFactory blackTeaFactory = new BlackTeaFactory();
blackTeaFactory.setTeaName("puer", "普洱茶");
抽象工厂模式
抽象工厂模式是工厂方法模式的扩展,它不再是创建单一类型的对象,而是创建一系列相关联的对象。
在本例中,红茶工厂为了迎合当地市场需求,丰富其产品线,引入了新的产品:奶茶;而绿茶工厂引入了果汁。如果使用工厂方法模式,我们还得新增奶茶和果汁工厂及对应的奶茶和果汁实体类,万一以后还新增产品,则添加的类越来越多。
在这里,我们可以将奶茶、果汁作为『饮料』类产品生产,将绿茶、红茶作为『茶叶』类产品生产。每个类型有对应的工厂类。
整体结构图:
- 新增抽象产品类,对应『茶叶』和『饮料』类;
public abstract class AbstractTea {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
public void sell() {
System.out.println("卖茶叶啦");
}
}
public abstract class AbstractDrinks {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void sell() {
System.out.println("卖饮料啦");
}
}
- 新建具体产品类
LongjingTea2
、MaojianTea2
、FruitJuice
、TeaWithMilk
:
public class LongjingTea2 extends AbstractTea{
@Override
public void sell() {
System.out.println("卖龙井茶啦");
}
}
public class MaojianTea2 extends AbstractTea{
@Override
public void sell() {
System.out.println("卖毛尖茶啦");
}
}
public class FruitJuice extends AbstractDrinks {
@Override
public void sell() {
System.out.println("卖果汁啦");
}
}
public class TeaWithMilk extends AbstractDrinks{
@Override
public void sell() {
System.out.println("卖奶茶啦");
}
}
- 新建抽象工厂接口
AbstractFactory
,用于声明创建不同种类产品的方法;
public abstract class AbstractFactory {
/**
* 生产茶叶
* @param teaTag 标签
* @return
*/
public abstract AbstractTea createTea(String teaTag);
/**
* 生产饮料
* @param type 类型
* @return
*/
public abstract AbstractDrinks createDrinks(String type);
}
- 新建具体工厂类
TeaFactory2
、DrinksFactory
,用于实现抽象工厂类中声明的方法,创建具体实例;
public class TeaFactory2 extends AbstractFactory{
@Override
public AbstractTea createTea(String teaTag) {
if ("longjing".equals(teaTag)) {
return new LongjingTea2();
} else if ("maojian".equals(teaTag)) {
return new MaojianTea2();
} else {
return null;
}
}
@Override
public AbstractDrinks createDrinks(String type) {
return null;
}
}
TeaFactory2
只负责生产龙井、毛尖等茶类。
public class DrinksFactory extends AbstractFactory{
@Override
public AbstractTea createTea(String teaTag) {
return null;
}
@Override
public AbstractDrinks createDrinks(String type) {
if ("fruitjuice".equals(type)) {
return new FruitJuice();
} else if ("teawithmilk".equals(type)) {
return new TeaWithMilk();
} else {
return null;
}
}
}
DrinksFactory
只负责生产果汁、奶茶等饮料。
- 在客户端中使用;
public static void main(String[] args) {
AbstractFactory abstractFactory = new DrinksFactory();
AbstractDrinks drinks = abstractFactory.createDrinks("fruitjuice");
drinks.sell();
AbstractFactory abstractFactory1 = new TeaFactory2();
AbstractTea tea = abstractFactory1.createTea("longjing");
tea.sell();
}
总结
工厂模式的核心就是由工厂类来负责合适对象的实例化,实现工厂模式的三种方式(简单工厂模式、工厂方法模式、抽象方法模式)之间可能存在许多重叠的地方,况且,这些模式也没有明确的定义,如果存在困惑也很正常。结合工作中的需求,选择合适自己最简单那种就行。
参考文献
[1]. 《Java设计模式及实践》