侧边栏壁纸
博主头像
昂洋编程 博主等级

鸟随鸾凤飞腾远,人伴贤良品自高

  • 累计撰写 71 篇文章
  • 累计创建 79 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录
MCA

工厂模式

Administrator
2023-02-02 / 0 评论 / 0 点赞 / 21 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
本文最后更新于2024-06-14,若内容或图片失效,请留言反馈。 部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

下面以模拟发放奖品业务为例来讲述工厂模式

  • 业务需求:用户参与抽奖,奖品的种类有: 打折券,免费优酷会员,小礼品

下面使用不同的方式来完成业务功能

方式一:原始开发方式

原始开发方式,不采用任何涉及模式,只是为了完成业务功能

定义多个实体类

  • 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);
    }
}

image-1675332690664

存在的问题

服务层有三个,并且在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));
    }
}

image-1675394312292

总结

image-1675393707923
简单工厂(静态工厂)先定义产品接口,不同的产品实现接口,工厂根据不同的产品动态的加载实现类

优缺点

优点

封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。

缺点:

增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。

工厂方法

概念

定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类

原理

工厂方法模式的目的很简单,就是封装对象创建的过程,提升创建对象方法的可复用性。
工厂方法模式的主要角色:

  • 抽象工厂:提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
  • 具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

实现

定义抽象工厂类

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);
    }

假如需要新增奖品,那么首先新增奖品类,然后新增奖品奖品接口实现类,再然后新增奖品工厂类实现,最后添加到工厂的工厂中即可使用

总结

image-1675840533271
对比简单工厂,简单工厂只有一个工厂,而工厂方法有一个抽象工厂和多个具体工厂,两者同样都需要产品接口,只不过简单工厂是直接使用那个唯一的工厂调用产品,而工厂方法是通过某一个具体的工厂去调用产品

优点

  1. 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
  2. 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;

缺点

每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

什么时候使用工厂方法

  1. 需要使用很多重复代码创建对象时,比如,DAO 层的数据对象、API 层的VO 对象等。
  2. 创建对象要访问外部信息或资源时,比如,读取数据库字段,获取访问授权token 信息,配置文件等。
  3. 创建需要统一管理生命周期的对象时,比如,会话信息、用户网页浏览轨迹对象等。
  4. 创建池化对象时,比如,连接池对象、线程池对象、日志对象等。这些对象的特性是:有限、可重用,使用工厂方法模式可以有效节约资源。
  5. 希望隐藏对象的真实类型时,比如,不希望使用者知道对象的真实构造函数参数等。

抽象工厂

介绍

抽象工厂模式比工厂方法模式的抽象程度更高. 在工厂方法模式中每一个具体工厂只需要生产一种具体产品,但是在抽象工厂模式中一个具体工厂可以生产一组相关的具体产品,这样一组产品被称为产品族.产品族中的每一个产品都分属于某一个产品继承等级结构

产品等级结构与产品族

为了更好的理解抽象工厂, 我们这里先引入两个概念:

产品等级结构 :

产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。

产品族

在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
image-1675841358147

在上图中,每一个具体工厂可以生产属于一个产品族的所有产品,例如海尔工厂生产海尔电视机、海尔空调和海尔冰箱,所生产的产品又位于不同的产品等级结构中. 如果使用工厂方法模式,上图所示的结构需要提供9个具体工厂,而使用抽象工厂模式只需要提供3个具体工厂,极大减少了系统中类的个数
image-1675843356728

抽象工厂模式概述

抽象工厂模式(Abstract Factory Pattern) 原始定义:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。

抽象工厂模式为创建一组对象提供了解决方案.与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,而是负责创建一个产品族.如下图:
image-1675841425563
抽象工厂模式中,每一个具体工厂都提供了多个工厂方法,用于生产多种不同类型的产品,这些产品构成一个产品族。

原理

在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法,用于产生多种不同类型的产品.这些产品构成了一个产品族.

抽象工厂模式的主要角色如下:

  • 抽象工厂(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());
    }
}

注意客户端持有抽象产品,构造方法中参数为抽象工厂,这样,就能在构造方法中使用抽象工厂生产具体产品

image-1675846855832

总结

从上面代码实现中我们可以看出,抽象工厂模式向使用(客户)方隐藏了下列变化:

  • 程序所支持的实例集合(具体工厂)的数目;
  • 当前是使用的实例集合中的哪一个实例;
  • 在任意给定时刻被实例化的具体类型;
    所以说,在理解抽象工厂模式原理时,你一定要牢牢记住“如何找到某一个类产品的正确共性功能”这个重点。

优点

  1. 对于不同产品系列有比较多共性特征时,可以使用抽象工厂模式,有助于提
    升组件的复用性.
  2. 当需要提升代码的扩展性并降低维护成本时,把对象的创建和使用过程分
    开,能有效地将代码统一到一个级别上
  3. 解决跨平台带来的兼容性问题

缺点

增加新的产品等级结构麻烦,需要对原有结构进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大不变,违背了开闭原则.

0

评论区