前言
先看个案例:【手机和手机店】在没有工厂的时候,手机店需要手机就需要自己创建,还得根据用户的选择进行创建不同的手机,如下图:
这样手机店直接与手机对象接触,就会对该对象耦合严重,假如我们添加新的手机品牌,还得修改手机店的create方法,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,将对象的创建封装在工厂内,实现使用者和对象解耦;所以说,工厂模式最大的优点就是:解耦。
工厂模式的主要目的是将对象的创建过程封装在工厂类中,客户端代码只需要关心从工厂获取对象的过程,而不需要了解对象的创建细节。这样可以降低代码的耦合度,提高代码的可维护性和可扩展性
一、简单工厂(静态工厂)
1、概述
简单工厂不是一种设计模式,反而比较像是一种编程习惯。把对象的创建和业务逻辑层分开,实现使用方(手机店)与对象(手机)的解耦。但工厂和产品之间还是存在耦合关系。
主要包含以下角色:
- 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品: 实现或者继承抽象产品的子类
- 具体工厂: 提供了创建产品的方法,调用者通过该方法来获取产品。
2、代码实现
抽象手机类【抽象产品】:
public abstract class Phone {
public abstract String getName();
}
手机产品【具体产品】:
public class HuaWei extends Phone {
@Override
public String getName() {
return "华为手机";
}
}
public class XiaoMi extends Phone {
@Override
public String getName() {
return "小米手机";
}
}
手机工厂【具体工厂】:
public class Factory {
public static Phone createPhone(String name) {
Phone phone = null;
if("小米".equals(name)) {
phone = new XiaoMi();
} else if("华为".equals(name)) {
phone = new HuaWei();
}
return phone;
}
}
手机店【使用者】:
public class Sotre {
public static Phone orderPhone(String name) {
return Factory.createPhone(name);
}
}
测试:
public class Test {
public static void main(String[] args) {
Phone xiaomi = Sotre.orderPhone("小米");
System.out.println(xiaomi.getName());
Phone huawei = Sotre.orderPhone("华为");
System.out.println(huawei.getName());
}
}
3、优缺点
优点:
封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。
缺点:
增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。
二、工厂方法模式
1、概述
在在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体的工作交给子类去做。 定义一个用于创建对象的接口(抽象工厂),让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。很好的解决了简单工厂的问题,遵循开闭原则。
工厂方法模式的主要角色:
- 抽象工厂: 提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
- 具体工厂: 主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
- 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品: 实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
2、代码实现
抽象手机类【抽象产品】:
public abstract class Phone {
public abstract String getName();
}
手机产品【具体产品】:
//小米手机
public class XiaoMi extends Phone {
@Override
public String getName() {
return "小米手机";
}
}
//华为手机
public class HuaWei extends Phone {
@Override
public String getName() {
return "华为手机";
}
}
抽象工厂:
class interface PhoneFactory {
Phone createPhone();
}
具体工厂:
//小米工厂
public class XiaoMiFactory implements PhoneFactory {
@Override
public Phone createPhone() {
return new XiaoMi();
}
}
//华为工厂
public class HuaWeiFactory implements PhoneFactory {
@Override
public Phone createPhone() {
return new HuaWei();
}
}
手机店【使用者】:
public class Store {
public Phone orderPhone(PhoneFactory factory) {
return factory.createPhone();
}
}
测试:
public class Test {
public static void main(String[] args) {
Store store = new Store();
Phone huaWei = store.orderPhone(new HuaWeiFactory());
Phone xiaomi = store.orderPhone(new XiaoMiFactory());
System.out.println(xiaomi.getName());
System.out.println(huaWei.getName());
}
}
3、优缺点
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
- 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
缺点:
- 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
三、抽象工厂模式
1、概述
抽象工厂模式是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产同一个等级的产品(小米手机,华为手机),而抽象工厂模式可生产多个等级的产品(小米家族,华为家族)。
抽象工厂模式的主要角色如下:
- 抽象工厂: 提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品(小米工厂和华为工厂的所有功能的抽象【创建手机,创建路由器】)。
- 具体工厂: 主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建(小米工厂造小米家族产品,华为工厂造华为家族产品)。
- 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品(小米和华为所拥有的同一系列产品的抽象【手机产品,路由器产品】)。
- 具体产品: 实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
2、代码实现
抽象工厂:
public interface Factory {
// 生产手机
Phone createPhone();
// 生产路由器
Router createRouter();
}
具体工厂:
//小米工厂
public class XiaoMiFactory implements Factory {
@Override
public Phone createPhone() {
return new XiaoMiPhone();
}
@Override
public Router createRouter() {
return new XiaoMiRouter();
}
}
//华为工厂
public class HuaWeiFactory implements Factory {
@Override
public Phone createPhone() {
return new HuaWeiPhone();
}
@Override
public Router createRouter() {
return new HuaWeiRouter();
}
}
抽象产品:
//手机产品
public abstract class Phone {
public abstract String getName();
}
//路由器类
public abstract class Router {
public abstract String getName();
}
具体产品:
public class XiaoMiPhone extends Phone{
@Override
public String getName() {
return "小米手机";
}
}
public class HuaWeiPhone extends Phone {
@Override
public String getName() {
return "华为手机";
}
}
public class XiaoMiRouter extends Router {
@Override
public String getName() {
return "小米路由器";
}
}
public class HuaWeiRouter extends Router {
@Override
public String getName() {
return "华为路由器";
}
}
手机店:
public class Store {
private Factory factory;
public void setFactory(Factory factory) {
this.factory = factory;
}
public Phone orderPhone(){
return factory.createPhone();
}
public Router orderRouter(){
return factory.createRouter();
}
}
测试:
public class Test {
public static void main(String[] args) {
Store store = new Store();
store.setFactory(new XiaoMiFactory());
Phone xiaomiPhone = store.orderPhone();
Router xiaomiRouter = store.orderRouter();
System.out.println(xiaomiPhone.getName());
System.out.println(xiaomiRouter.getName());
System.out.println("===========");
store.setFactory(new HuaWeiFactory());
Phone huaweiPhone = store.orderPhone();
Router huaweiRouter = store.orderRouter();
System.out.println(huaweiPhone.getName());
System.out.println(huaweiRouter.getName());
}
}
如果要加同一个产品族的话,只需要再加一个对应的工厂类即可,不需要修改其他的类。
3、优缺点
优点:
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:
当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
四、总结
- 以上述案例为例,没有工厂就是手机店直接造手机,使用者和对象高度耦合,新增品类时违背开闭原则,一个手机店造不同手机违背单一职责原则;
- 由此引出简单工厂,手机店只需要和工厂打交道,售卖手机,不负责造手机的过程,实现手机店和对象的解耦,但是工厂和对象还是存在上述问题;
- 由此工厂在向上抽象出“工厂规范”,形成工厂方法模式,不同的工厂负责不同的职责,添加新的品类时增加对应工厂和产品即可;
- 在往下走,工厂做大做强以后,不只是可以生产手机,还添加了新的产品路由器,形成抽象工厂模式。
- 工厂方法模式是针对单一的品类进行的实现,二抽象工厂是针对多个品类(产品族)的实现。