下面以模拟发放奖品业务为例来讲述工厂模式
- 业务需求:用户参与抽奖,奖品的种类有: 打折券,免费优酷会员,小礼品
下面使用不同的方式来完成业务功能
方式一:原始开发方式
原始开发方式,不采用任何涉及模式,只是为了完成业务功能
定义多个实体类
- AwardInfo
package com.imysh.zmy.mca.designpattern.factory2.origin.eneity;
import lombok.Data;
import java.util.Map;
/**
* @author zhangmy
* @date 2023/2/2 17:01
* @description 获奖信息对应实体类
*/
@Data
public class AwardInfo {
/**
* 全局用户id
*/
private String uid;
/**
* 奖品类型(1:打折券 2:优酷会员 3:小礼品)
*/
private Integer awardType;
/**
* 奖品编号
*/
private String awardNumber;
/**
* 额外的获奖信息封装
*/
private Map<String, String> extMap;
}
- DiscountInfo
package com.imysh.zmy.mca.designpattern.factory2.origin.eneity;
/**
* @author zhangmy
* @date 2023/2/2 17:08
* @description 打折券信息
*/
public class DiscountInfo {
// 属性省略
}
- YouKuMember
package com.imysh.zmy.mca.designpattern.factory2.origin.eneity;
/**
* @author zhangmy
* @date 2023/2/2 17:10
* @description 优酷会员信息
*/
public class YouKuMember {
// 省略属性
}
- SmallGiftInfo
package com.imysh.zmy.mca.designpattern.factory2.origin.eneity;
import lombok.Data;
/**
* @author zhangmy
* @date 2023/2/2 17:10
* @description 小礼品信息
*/
@Data
public class SmallGiftInfo {
private String userName;
private String userPhone;
private String orderId;
private String address;
}
- DiscountResult
package com.imysh.zmy.mca.designpattern.factory2.origin.eneity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* @author zhangmy
* @date 2023/2/2 17:13
* @description 打折券响应结果封装
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class DiscountResult {
private String status;
private String message;
}
定义服务类
- DiscountService
package com.imysh.zmy.mca.designpattern.factory2.origin.service;
import com.imysh.zmy.mca.designpattern.factory2.origin.eneity.DiscountResult;
/**
* @author zhangmy
* @date 2023/2/2 17:19
* @description 打折券服务
*/
public class DiscountService {
/**
* 发送打折券
* @param uid 用户id
* @param awardNumber 奖品编号
* @return
*/
public DiscountResult sendDiscount(String uid, String awardNumber) {
System.out.println("向用户发放打折券成功:" + uid + "," + awardNumber);
return new DiscountResult("200", "向用户发放打折券成功");
}
}
- YouKuMemberService
package com.imysh.zmy.mca.designpattern.factory2.origin.service;
import com.imysh.zmy.mca.designpattern.factory2.origin.eneity.DiscountResult;
/**
* @author zhangmy
* @date 2023/2/2 17:23
* @description 优酷会员服务
*/
public class YouKuMemberService {
/**
* 开通优酷会员
* @param userPhone
* @param awardNumber
* @return
*/
public DiscountResult activeMember(String userPhone, String awardNumber) {
System.out.println("开通优酷会员成功:" + userPhone + "," + awardNumber);
return new DiscountResult("200", "开通优酷会员成功");
}
}
- SmallGiftService
package com.imysh.zmy.mca.designpattern.factory2.origin.service;
import com.imysh.zmy.mca.designpattern.factory2.origin.eneity.SmallGiftInfo;
/**
* @author zhangmy
* @date 2023/2/2 17:23
* @description 小礼品服务
*/
public class SmallGiftService {
public Boolean giveSmallGift(SmallGiftInfo smallGiftInfo ) {
System.out.println("向用户放松小礼品成功,用户注意查收!" + smallGiftInfo.toString());
return true;
}
}
定义controller
package com.imysh.zmy.mca.designpattern.factory2.origin.controller;
import com.imysh.zmy.mca.designpattern.factory2.origin.eneity.AwardInfo;
import com.imysh.zmy.mca.designpattern.factory2.origin.eneity.SmallGiftInfo;
import com.imysh.zmy.mca.designpattern.factory2.origin.service.DiscountService;
import com.imysh.zmy.mca.designpattern.factory2.origin.service.SmallGiftService;
import com.imysh.zmy.mca.designpattern.factory2.origin.service.YouKuMemberService;
import java.util.UUID;
/**
* @author zhangmy
* @date 2023/2/2 17:37
* @description 发放奖品接口
*/
public class DeliverController {
/**
* 根据类型发放奖品 (1:打折券 2:优酷会员 3:小礼品)
* @param awardInfo
*/
public void awardToUser(AwardInfo awardInfo) {
Integer awardType = awardInfo.getAwardType();
if (awardType == 1) {
DiscountService discountService = new DiscountService();
System.out.println("打折券发放成功" + discountService.sendDiscount(awardInfo.getUid(), awardInfo.getAwardNumber()));
} else if (awardType == 2) {
YouKuMemberService youKuMemberService = new YouKuMemberService();
System.out.println("优酷会员发放成功" + youKuMemberService.activeMember(awardInfo.getExtMap().get("phone"), awardInfo.getAwardNumber()));
} else {
SmallGiftService smallGiftService = new SmallGiftService();
SmallGiftInfo smallGiftInfo = new SmallGiftInfo();
smallGiftInfo.setUserName(awardInfo.getExtMap().get("username"));
smallGiftInfo.setAddress(awardInfo.getExtMap().get("address"));
smallGiftInfo.setUserName(awardInfo.getExtMap().get("phone"));
smallGiftInfo.setOrderId(UUID.randomUUID().toString());
Boolean b = smallGiftService.giveSmallGift(smallGiftInfo);
System.out.println("小礼品发放成功");
}
}
}
测试
package com.imysh.zmy.mca.designpattern.factory2.origin;
import com.imysh.zmy.mca.designpattern.factory2.origin.controller.DeliverController;
import com.imysh.zmy.mca.designpattern.factory2.origin.eneity.AwardInfo;
/**
* @author zhangmy
* @date 2023/2/2 17:51
* @description 原始方式测试
*/
public class OriginTest {
public static void main(String[] args) {
AwardInfo awardInfo = new AwardInfo();
awardInfo.setUid("1001");
awardInfo.setAwardType(1);
awardInfo.setAwardNumber("DEL12345");
DeliverController deliverController = new DeliverController();
deliverController.awardToUser(awardInfo);
}
}
存在的问题
服务层有三个,并且在controller里边做的if else判断,如果需要增加奖品类型,需要修改源码,这样不灵活,更不符合开闭原则
下面我们采用工厂模式来实现这个功能
简单工厂
介绍
简单工厂不是一种设计模式,反而比较像是一种编程习惯。简单工厂模式又叫做静态工厂方法模式(static Factory Method pattern),它是通过使用静态方法接收不同的参数来返回不同的实例对象
实现方式
定义一个工厂类,根据传入的参数不同返回不同的实例,被创建的实例具有共同的父类或接口
适用场景
(1)需要创建的对象较少。
(2)客户端不关心对象的创建过程。
原理
简单工厂包含如下角色:
- 抽象产品 :定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品 :实现或者继承抽象产品的子类
- 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。
示例
定义实体类
- AwardInfo
package com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity;
import lombok.Data;
import java.util.Map;
/**
* @author zhangmy
* @date 2023/2/2 17:01
* @description 获奖信息对应实体类
*/
@Data
public class AwardInfo {
/**
* 全局用户id
*/
private String uid;
/**
* 奖品类型(1:打折券 2:优酷会员 3:小礼品)
*/
private Integer awardType;
/**
* 奖品编号
*/
private String awardNumber;
/**
* 额外的获奖信息封装
*/
private Map<String, String> extMap;
}
- SmallGiftInfo
package com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity;
import lombok.Data;
/**
* @author zhangmy
* @date 2023/2/2 17:10
* @description 小礼品信息
*/
@Data
public class SmallGiftInfo {
private String userName;
private String userPhone;
private String orderId;
private String address;
}
- ResponseResult
package com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* @author zhangmy
* @date 2023/2/2 17:13
* @description 打折券响应结果封装
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class ResponseResult {
private String status;
private String message;
private Object data;
}
ResponseResult中多加了一个data,为了看上去更加正规
另外因为原始方法中YouKuMember类和DiscountInfo都是空的,所以这里咱们不需要定义了
定义Service
这里我们只需要定义一个公共接口,然后再实现三个不同的奖品实现类即可
- IFreeGoods
package com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.AwardInfo;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.ResponseResult;
/**
* @author zhangmy
* @date 2023/2/3 9:48
* @description 奖品发放接口
*/
public interface IFreeGoods {
/**
* 发放奖品
* @param awardInfo
* @return
*/
ResponseResult sendAward(AwardInfo awardInfo);
}
- DiscountFreeGoods
package com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.AwardInfo;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.ResponseResult;
/**
* @author zhangmy
* @date 2023/2/3 9:52
* @description 打折券服务
*/
public class DiscountFreeGoods implements IFreeGoods{
@Override
public ResponseResult sendAward(AwardInfo awardInfo) {
System.out.println("向用户发放打折券成功:" + awardInfo.getUid() + "," + awardInfo.getAwardNumber());
return new ResponseResult("200", "向用户发放打折券成功",null);
}
}
- YouKuMemberFreeGoods
package com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.AwardInfo;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.ResponseResult;
/**
* @author zhangmy
* @date 2023/2/3 9:54
* @description
*/
public class YouKuMemberFreeGoods implements IFreeGoods{
@Override
public ResponseResult sendAward(AwardInfo awardInfo) {
System.out.println("开通优酷会员成功:" + awardInfo.getExtMap().get("phone") + "," + awardInfo.getAwardNumber());
return new ResponseResult("200", "开通优酷会员成功",null);
}
}
- SmallGiftFreeGoods
package com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.AwardInfo;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.ResponseResult;
/**
* @author zhangmy
* @date 2023/2/3 10:24
* @description
*/
public class SmallGiftFreeGoods implements IFreeGoods {
@Override
public ResponseResult sendAward(AwardInfo awardInfo) {
System.out.println("向用户放松小礼品成功,用户注意查收!" + awardInfo.toString());
return new ResponseResult("200", "向用户放松小礼品成功,用户注意查收!",null);
}
}
定义工厂类
package com.imysh.zmy.mca.designpattern.factory2.simpleFactory.factory;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.DiscountFreeGoods;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.IFreeGoods;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.SmallGiftFreeGoods;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.YouKuMemberFreeGoods;
/**
* @author zhangmy
* @date 2023/2/3 10:46
* @description 奖品工厂类
*/
public class FreeGoodFactory {
/**
* 获取奖品实例
* @param awardType
* @return
*/
public static IFreeGoods getInstance(Integer awardType) {
IFreeGoods freeGoods = null;
if (awardType == 1) {
freeGoods = new DiscountFreeGoods();
} else if (awardType == 2) {
freeGoods = new YouKuMemberFreeGoods();
} else {
freeGoods = new SmallGiftFreeGoods();
}
return freeGoods;
}
}
在工厂类中我们根据不同的奖品类型生成不同的奖品方法实现类
定义controller
package com.imysh.zmy.mca.designpattern.factory2.simpleFactory.controller;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.AwardInfo;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.ResponseResult;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.factory.FreeGoodFactory;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.IFreeGoods;
/**
* @author zhangmy
* @date 2023/2/3 10:54
* @description 奖品方法接口
*/
public class DeliverController {
public ResponseResult sendAward(AwardInfo awardInfo) {
IFreeGoods freeGoods = FreeGoodFactory.getInstance(awardInfo.getAwardType());
return freeGoods.sendAward(awardInfo);
}
}
测试
package com.imysh.zmy.mca.designpattern.factory2.simpleFactory;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.AwardInfo;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.controller.DeliverController;
import java.util.HashMap;
import java.util.Map;
/**
* @author zhangmy
* @date 2023/2/3 10:56
* @description 简单工厂测试
*/
public class SimpleFactoryTest {
public static void main(String[] args) {
DeliverController deliverController = new DeliverController();
AwardInfo awardInfo = new AwardInfo();
awardInfo.setUid("1002");
awardInfo.setAwardType(2);
awardInfo.setAwardNumber("DW12345");
Map<String,String> map = new HashMap<>();
map.put("phone","13512341234");
awardInfo.setExtMap(map);
System.out.println(deliverController.sendAward(awardInfo));
}
}
总结
简单工厂(静态工厂)先定义产品接口,不同的产品实现接口,工厂根据不同的产品动态的加载实现类
优缺点
优点
封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。
缺点:
增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。
工厂方法
概念
定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类
原理
工厂方法模式的目的很简单,就是封装对象创建的过程,提升创建对象方法的可复用性。
工厂方法模式的主要角色:
- 抽象工厂:提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
- 具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
- 抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
实现
定义抽象工厂类
package com.imysh.zmy.mca.designpattern.factory2.factoryMethod.factory;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.IFreeGoods;
/**
* @author zhangmy
* @date 2023/2/8 13:52
* @description 抽象工厂类
*/
public interface FreeGoodsFactory {
/**
* 获取实例
* @return
*/
IFreeGoods getInstance();
}
里边就一个getInstance方法,获取的是具体的奖品,IFreeGoods用的是简单工厂中的IFreeGoods
定义具体的工厂类
- DiscountFreeGoodsFactory
package com.imysh.zmy.mca.designpattern.factory2.factoryMethod.factory;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.DiscountFreeGoods;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.IFreeGoods;
/**
* @author zhangmy
* @date 2023/2/8 13:55
* @description 打折券具体工厂
*/
public class DiscountFreeGoodsFactory implements FreeGoodsFactory {
@Override
public IFreeGoods getInstance() {
// 返回具体的产品
return new DiscountFreeGoods();
}
}
- YouKuMemberFreeGoodsFactory
package com.imysh.zmy.mca.designpattern.factory2.factoryMethod.factory;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.IFreeGoods;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.YouKuMemberFreeGoods;
/**
* @author zhangmy
* @date 2023/2/8 13:56
* @description 优酷会员具体工厂
*/
public class YouKuMemberFreeGoodsFactory implements FreeGoodsFactory{
@Override
public IFreeGoods getInstance() {
// 返回具体的产品
return new YouKuMemberFreeGoods();
}
}
- SmallGiftFreeGoodsFactory
package com.imysh.zmy.mca.designpattern.factory2.factoryMethod.factory;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.IFreeGoods;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.SmallGiftFreeGoods;
/**
* @author zhangmy
* @date 2023/2/8 13:59
* @description 小礼品具体工厂
*/
public class SmallGiftFreeGoodsFactory implements FreeGoodsFactory {
@Override
public IFreeGoods getInstance() {
// 返回具体的产品
return new SmallGiftFreeGoods();
}
}
返回的三个具体产品类也都是用的简单工厂中那三个
定义controller
package com.imysh.zmy.mca.designpattern.factory2.factoryMethod.controller;
import com.imysh.zmy.mca.designpattern.factory2.factoryMethod.factory.DiscountFreeGoodsFactory;
import com.imysh.zmy.mca.designpattern.factory2.factoryMethod.factory.FreeGoodsFactory;
import com.imysh.zmy.mca.designpattern.factory2.factoryMethod.factory.SmallGiftFreeGoodsFactory;
import com.imysh.zmy.mca.designpattern.factory2.factoryMethod.factory.YouKuMemberFreeGoodsFactory;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.AwardInfo;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.enetity.ResponseResult;
import com.imysh.zmy.mca.designpattern.factory2.simpleFactory.service.IFreeGoods;
/**
* @author zhangmy
* @date 2023/2/3 10:54
* @description 奖品方法接口
*/
public class DeliverController {
public ResponseResult sendAward(AwardInfo awardInfo) {
// 获取具体工厂
FreeGoodsFactory freeGoodsFactory;
if (awardInfo.getAwardType() == 1) {
freeGoodsFactory = new DiscountFreeGoodsFactory();
} else if (awardInfo.getAwardType() == 2) {
freeGoodsFactory = new YouKuMemberFreeGoodsFactory();
} else {
freeGoodsFactory = new SmallGiftFreeGoodsFactory();
}
// 拿到具体的奖品
IFreeGoods freeGoods = freeGoodsFactory.getInstance();
// 发送奖品
return freeGoods.sendAward(awardInfo);
}
}
通过奖品类型获取具体的工厂,然后通过具体工厂获取具体的奖品,然后发放奖品
上面的实现方式中controller还是需要if else的判断,这里我们再优化一下,定义一个工厂的工厂
package com.imysh.zmy.mca.designpattern.factory2.factoryMethod.factory;
import java.util.HashMap;
import java.util.Map;
/**
* @author zhangmy
* @date 2023/2/8 14:56
* @description 工厂的工厂
*/
public class FreeGoodsFactoryMap {
private static final Map<Integer, FreeGoodsFactory> cachedFactories = new HashMap<>();
static {
cachedFactories.put(1, new DiscountFreeGoodsFactory());
cachedFactories.put(2, new YouKuMemberFreeGoodsFactory());
cachedFactories.put(3, new SmallGiftFreeGoodsFactory());
}
public static FreeGoodsFactory getParserFactory(Integer type) {
return cachedFactories.get(type) != null ? cachedFactories.get(type) : null;
}
}
工厂的工厂中使用map初始化好所有的工厂,这样我们在用的时候就可以根据类型从map中取就行
public ResponseResult sendAward(AwardInfo awardInfo) {
// 获取具体工厂
FreeGoodsFactory freeGoodsFactory = FreeGoodsFactoryMap.getParserFactory(awardInfo.getAwardType());
// 拿到具体的奖品
IFreeGoods freeGoods = freeGoodsFactory.getInstance();
// 发送奖品
return freeGoods.sendAward(awardInfo);
}
假如需要新增奖品,那么首先新增奖品类,然后新增奖品奖品接口实现类,再然后新增奖品工厂类实现,最后添加到工厂的工厂中即可使用
总结
对比简单工厂,简单工厂只有一个工厂,而工厂方法有一个抽象工厂和多个具体工厂,两者同样都需要产品接口,只不过简单工厂是直接使用那个唯一的工厂调用产品,而工厂方法是通过某一个具体的工厂去调用产品
优点
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
- 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
缺点
每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
什么时候使用工厂方法
- 需要使用很多重复代码创建对象时,比如,DAO 层的数据对象、API 层的VO 对象等。
- 创建对象要访问外部信息或资源时,比如,读取数据库字段,获取访问授权token 信息,配置文件等。
- 创建需要统一管理生命周期的对象时,比如,会话信息、用户网页浏览轨迹对象等。
- 创建池化对象时,比如,连接池对象、线程池对象、日志对象等。这些对象的特性是:有限、可重用,使用工厂方法模式可以有效节约资源。
- 希望隐藏对象的真实类型时,比如,不希望使用者知道对象的真实构造函数参数等。
抽象工厂
介绍
抽象工厂模式比工厂方法模式的抽象程度更高. 在工厂方法模式中每一个具体工厂只需要生产一种具体产品,但是在抽象工厂模式中一个具体工厂可以生产一组相关的具体产品,这样一组产品被称为产品族.产品族中的每一个产品都分属于某一个产品继承等级结构
产品等级结构与产品族
为了更好的理解抽象工厂, 我们这里先引入两个概念:
产品等级结构 :
产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
产品族
在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
在上图中,每一个具体工厂可以生产属于一个产品族的所有产品,例如海尔工厂生产海尔电视机、海尔空调和海尔冰箱,所生产的产品又位于不同的产品等级结构中. 如果使用工厂方法模式,上图所示的结构需要提供9个具体工厂,而使用抽象工厂模式只需要提供3个具体工厂,极大减少了系统中类的个数
抽象工厂模式概述
抽象工厂模式(Abstract Factory Pattern) 原始定义:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
抽象工厂模式为创建一组对象提供了解决方案.与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,而是负责创建一个产品族.如下图:
抽象工厂模式中,每一个具体工厂都提供了多个工厂方法,用于生产多种不同类型的产品,这些产品构成一个产品族。
原理
在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法,用于产生多种不同类型的产品.这些产品构成了一个产品族.
抽象工厂模式的主要角色如下:
- 抽象工厂(Abstract Factory)
它声明了一种用于创建一族产品的方法,每一个方法对应一种产品. - 具体工厂(Concrete Factory)
主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建. - 抽象产品(Product)
定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。 - 具体产品(ConcreteProduct)
实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。
实现
抽象产品
- AbstractTV
package com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product;
/**
* @author zhangmy
* @date 2023/2/8 16:12
* @description 抽象产品,定义产品规范,描述了产品的主要特征和功能
*/
public interface AbstractTV {
}
- AbstractFreezer
package com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product;
/**
* @author zhangmy
* @date 2023/2/8 16:16
* @description 抽象产品,定义产品规范,描述了产品的主要特征和功能
*/
public interface AbstractFreezer {
}
具体产品
- HairTV
package com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product;
/**
* @author zhangmy
* @date 2023/2/8 16:15
* @description 海尔TB具体产品
*/
public class HairTV implements AbstractTV{
}
- HisenceTV
package com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product;
/**
* @author zhangmy
* @date 2023/2/8 16:15
* @description 海信TV具体产品
*/
public class HisenceTV implements AbstractTV{
}
- HariFreezer
package com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product;
/**
* @author zhangmy
* @date 2023/2/8 16:17
* @description 海尔冰箱具体产品
*/
public class HariFreezer implements AbstractFreezer {
}
- HisenceFreezer
package com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product;
/**
* @author zhangmy
* @date 2023/2/8 16:17
* @description 海信冰箱具体产品
*/
public class HisenceFreezer implements AbstractFreezer {
}
抽象工厂
- AppliancesFactory
package com.imysh.zmy.mca.designpattern.factory2.abstractFactory.factory;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product.AbstractFreezer;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product.AbstractTV;
/**
* @author zhangmy
* @date 2023/2/8 16:38
* @description 家用电器工厂:在一个工厂中可以声明多个抽工厂方法,用于创建不同类型的产品
*/
public interface AppliancesFactory {
/**
* 生产TB
* @return
*/
AbstractTV createTV();
/**
* 生产冰箱
* @return
*/
AbstractFreezer createFreezer();
}
具体工厂
- HairFactory
package com.imysh.zmy.mca.designpattern.factory2.abstractFactory.factory;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product.AbstractFreezer;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product.AbstractTV;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product.HairTV;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product.HariFreezer;
/**
* @author zhangmy
* @date 2023/2/8 16:41
* @description 海尔具体工厂类
*/
public class HairFactory implements AppliancesFactory{
@Override
public AbstractTV createTV() {
return new HairTV();
}
@Override
public AbstractFreezer createFreezer() {
return new HariFreezer();
}
}
- HisenceFactory
package com.imysh.zmy.mca.designpattern.factory2.abstractFactory.factory;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product.AbstractFreezer;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product.AbstractTV;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product.HisenceFreezer;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product.HisenceTV;
/**
* @author zhangmy
* @date 2023/2/8 16:42
* @description 海信具体工厂类
*/
public class HisenceFactory implements AppliancesFactory{
@Override
public AbstractTV createTV() {
return new HisenceTV();
}
@Override
public AbstractFreezer createFreezer() {
return new HisenceFreezer();
}
}
客户端
package com.imysh.zmy.mca.designpattern.factory2.abstractFactory;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.factory.AppliancesFactory;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.factory.HairFactory;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product.AbstractFreezer;
import com.imysh.zmy.mca.designpattern.factory2.abstractFactory.product.AbstractTV;
/**
* @author zhangmy
* @date 2023/2/8 16:47
* @description 客户端:需持有抽象产品,在构造方法中参数定义为抽象工厂,使用抽象工厂生产家电
*/
public class Client {
private AbstractTV tv;
private AbstractFreezer freezer;
public Client(AppliancesFactory factory) {
// 使用抽象工厂来生产家电
this.tv = factory.createTV();
this.freezer = factory.createFreezer();
}
public AbstractTV getTv() {
return tv;
}
public void setTv(AbstractTV tv) {
this.tv = tv;
}
public AbstractFreezer getFreezer() {
return freezer;
}
public void setFreezer(AbstractFreezer freezer) {
this.freezer = freezer;
}
public static void main(String[] args) {
Client client = new Client(new HairFactory());
System.out.println(client.getTv());
System.out.println(client.getFreezer());
}
}
注意客户端持有抽象产品,构造方法中参数为抽象工厂,这样,就能在构造方法中使用抽象工厂生产具体产品
总结
从上面代码实现中我们可以看出,抽象工厂模式向使用(客户)方隐藏了下列变化:
- 程序所支持的实例集合(具体工厂)的数目;
- 当前是使用的实例集合中的哪一个实例;
- 在任意给定时刻被实例化的具体类型;
所以说,在理解抽象工厂模式原理时,你一定要牢牢记住“如何找到某一个类产品的正确共性功能”这个重点。
优点
- 对于不同产品系列有比较多共性特征时,可以使用抽象工厂模式,有助于提
升组件的复用性. - 当需要提升代码的扩展性并降低维护成本时,把对象的创建和使用过程分
开,能有效地将代码统一到一个级别上 - 解决跨平台带来的兼容性问题
缺点
增加新的产品等级结构麻烦,需要对原有结构进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大不变,违背了开闭原则.
评论区