设计模式-抽象工厂模式

在前面介绍的 工厂方法模式是考虑的一类产品的生产,如手机工厂只生产手机,也就是说,工厂方法模式只考虑生产同等级产品,但是在现实生活中,许多工厂是综合型的工厂,手机工厂不仅仅只生产手机,还生产耳机、手机壳、充电宝等等

本节要介绍的抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族

抽象工厂模式与工厂方法模式最大的区别:抽象工厂中每个工厂可以创建多种类的产品;而工厂方法每个工厂只能创建一类

1 模式介绍

1.1 定义

抽象工厂(AbstractFactory)模式的定义:是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

1.2 模式组成

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

组成(角色) 关系 作用 抽象产品(Product) 具体产品的父类 描述具体产品的公共接口 具体产品(Concrete Product) 抽象产品的子类;工厂类创建的目标类 描述生产的具体产品 抽象工厂(Creator) 具体工厂的父类 描述具体工厂的公共接口 具体工厂(Concrete Creator) 抽象工厂的子类;被外界调用 描述具体工厂;实现FactoryMethod工厂方法创建产品的实例

设计模式-抽象工厂模式

从图上面的图可以看出抽象工厂模式的结构同工厂方法模式的结构相似,不同的是其产品的种类不止一个,所以创建产品的方法也不止一个。

1.3 解决的问题

解决工厂方法模式的缺点

每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度,工厂方法可以解决这一问题

2 实例讲解:

继续工厂方法模式中手机专卖店 Store卖手机的例子,不了解的可以去看看工厂方法模式中手机专卖店的例子。目前 Store卖有两种手机,一个苹果手机,一个索尼手机,此时客户需要买耳机,那么专卖店就必须要进货,采购不同厂商品牌的耳机(苹果耳机、索尼耳机)。那么就必须要新增耳机工厂(苹果耳机工厂、索尼耳机工厂),而且还是不同品牌的耳机,假如后面又增加了一个品牌(比如小米)的手机、耳机、充电器、手机壳,此时使用工厂方法模式就要增加小米手机工厂、耳机工厂、充电器工厂、手机壳工厂,想想对这一大堆工厂的管理就很麻烦,那么使用抽象工厂模式就能解决这种问题

2.1 使用步骤

步骤1: 创建抽象产品类 ,定义具体产品的公共抽象接口;

/**
 * 耳机
 *
 * @author mrxccc
 * @create 2020/9/23
 */
public abstract class Headset {
    /**
     * 品牌
     */
    protected String brand;

    abstract void play();

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }
}

/**
 * @author mrxccc
 * @create 2020/9/23
 */
public abstract class Phone {
    /**
     * 品牌
     */
    protected String brand;

    /**
     * 操作系统
     */
    protected String os;

    /**
     * 充电
     */
    public abstract void charge();

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getOs() {
        return os;
    }

    public void setOs(String os) {
        this.os = os;
    }
}

步骤2: 创建抽象工厂类,定义具体工厂的公共接口

/**
 * 这里和工厂方法模式不同,定义了同一等级的不同产品
 * @author mrxccc
 * @create 2020/9/23
 */
public interface Factory {
    Phone getPhone();

    Headset getHeadset();
}

步骤3:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;

/**
 * 苹果工厂
 * @author mrxccc
 * @create 2020/9/23
 */
public class AppleFactory implements Factory{
    @Override
    public ApplePhone getPhone() {
        ApplePhone applePhone = new ApplePhone();
        applePhone.setBrand("Apple");
        return applePhone;
    }

    @Override
    public AppleHeadset getHeadset() {
        AppleHeadset appleHeadset = new AppleHeadset();
        appleHeadset.setBrand("Apple");
        return appleHeadset;
    }

}

/**
 * 索尼工厂
 *
 * @author mrxccc
 * @create 2020/9/23
 */
public class SonyFactory extends Factory {
    @Override
    public SonyPhone getPhone() {
        SonyPhone sonyPhone = new SonyPhone();
        sonyPhone.setBrand("Sony");
        return sonyPhone;
    }

    @Override
    public SonyHeadset getHeadset() {
        SonyHeadset sonyHeadset = new SonyHeadset();
        sonyHeadset.setBrand("Sony");
        return sonyHeadset;
    }

}

步骤4: 创建抽象产品类

/**
 * @author mrxccc
 * @create 2020/9/23
 */
public abstract class Phone {
    /**
     * 品牌
     */
    protected String brand;

    /**
     * 操作系统
     */
    protected String os;

    /**
     * 充电
     */
    public abstract void charge();

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getOs() {
        return os;
    }

    public void setOs(String os) {
        this.os = os;
    }
}

/**
 * 耳机
 *
 * @author mrxccc
 * @create 2020/9/23
 */
public abstract class Headset {
    /**
     * 品牌
     */
    protected String brand;

    abstract void play();

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

}

步骤5: 创建具体产品类(继承抽象产品类), 定义生产的具体产品;

/**
 * 苹果手机
 *
 * @author mrxccc
 * @create 2020/9/23
 */
public class ApplePhone extends Phone {
    @Override
    public void charge() {
        System.out.println("普通充电");
    }
}
/**
 * 索尼手机
 *
 * @author mrxccc
 * @create 2020/9/23
 */
public class SonyPhone extends Phone {
    @Override
    public void charge() {
        System.out.println("快充");
    }
}
/**
 * 苹果耳机
 * @author mrxccc
 * @create 2020/9/23
 */
public class AppleHeadset extends Headset{
    @Override
    void play() {
        // Apple 耳机播放逻辑 ...

        System.out.println("Apple 耳机播放完成");
    }
}
/**
 * 索尼耳机
 *
 * @author mrxccc
 * @create 2020/9/23
 */
public class SonyHeadset extends Headset {
    @Override
    void play() {
        // Sony 耳机播放逻辑...

        System.out.println("Sony 耳机播放完成");
    }
}

步骤6:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例

/**
 * 专卖店D:抽象工厂模式
 * @author mrxccc
 * @create 2020/9/23
 */
public class StoreD {
    private Factory factory;

    public StoreD(Factory factory) {
        super();
        this.factory = factory;
    }

    /**
     * 补充手机
     */
    public void supplyPhone() {
        Phone phone = factory.getPhone();
        // 补充手机逻辑...

        System.out.println("补充" + phone.getBrand() + "手机完成");
    }

    /**
     * 补充耳机
     */
    public void supplyHeadset() {
        Headset headset = factory.getHeadset();
        // 补充耳机逻辑...

        System.out.println("补充" + headset.getBrand() + "耳机完成");
    }

    public static void main(String[] args) {
        StoreD storeC = new StoreD(new SonyFactory());
        storeC.supplyPhone();
        storeC.supplyHeadset();
    }
}

结果

补充Sony手机完成
补充Sony耳机完成

3.应用场景

抽象工厂模式最早的应用是用于创建属于不同操作系统的视窗构件。如java 的 AWT 中的 Button 和 Text 等构件在 Windows 和 UNIX 中的本地实现是不同的。

抽象工厂模式通常适用于以下场景:

  1. 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
  2. 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
  3. 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

4.模式扩展

抽象工厂模式的扩展有一定的”开闭原则”倾斜性:

  1. 当增加一个新的产品族( 是产品族,不是某个产品)时只需增加一个新的具体工厂,不需要修改原代码,满足开闭原则。
  2. 当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改,不满足开闭原则。

另一方面,当系统中只存在一个等级结构的产品时,抽象工厂模式将退化到工厂方法模式。

源码:设计模式

其他设计模式介绍:
设计模式-工厂方法模式
设计模式-抽象工厂模式
设计模式-建造者模式

更多精彩内容:[mrxccc](

Original: https://www.cnblogs.com/mrxccc/p/16504770.html
Author: 狮子挽歌丿
Title: 设计模式-抽象工厂模式

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/588646/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • java基础4.20

    1.是否可以从一个static方法内部发出对非static方法的调用?不可以。因为非static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而st…

    Java 2023年6月5日
    042
  • synology drive client 连接失败

    添加路由映射,别管你的nas端口是多少,这玩意默认端口就是6690 Original: https://www.cnblogs.com/limumu/p/16385174.html…

    Java 2023年6月6日
    089
  • Linux自动备份MySQL、删除过期备份

    背景:阿里云服务器,只有一个数据库 需求:每天凌晨备份数据库、超过7天自动删除 方法: 一、新建执行脚本(/home/dbback/bkmscm.sh) 二、授予脚本权限 chmo…

    Java 2023年6月8日
    071
  • Java 内存模型

    《Java虚拟机规范》中曾试图定义一种”Java内存模型”(Java Memory Model,JMM)来 屏蔽各种硬件和操作系统的内存访问差异,以实现让J…

    Java 2023年5月29日
    078
  • MySQL 优化篇(二)

    分析查询语句:EXPLAIN 定位了查询慢的SQL之后,我们就可以使用EXPLAIN或DESCRIBE工具做针对性的分析查询语句。DESCRIBE 语句的使用方法与EXPLAIN语…

    Java 2023年6月8日
    075
  • git没有提交的代码如何迁移到新建分支

    在接到需求以后,直接在master上开发了,到提交的时候才想起来忘记新建版本分支了,直接提交到master会影响到其他人。这时候就想着将本地编辑的代码,没有提交的代码暂存起来,然后…

    Java 2023年6月8日
    087
  • Disruptor生产和消费模式详解及高级应用(并行模式)

    小伙伴们大家好,昨天的文章,带着大家扒开了Disruptor华丽的外衣,最重要的是我们知道了Disruptor高性能的原因几个重要的原因, 引入环形的数组结构:数组元素不会被回收,…

    Java 2023年6月15日
    054
  • 干货分享之Spring框架源码解析01-(xml配置解析)

    记录并分享一下本人学习spring源码的过程,有什么问题或者补充会持续更新。欢迎大家指正! 环境: spring5.X + idea Spring 是一个工厂,是一个负责对象的创建…

    Java 2023年6月5日
    094
  • Nginx的安装与运行

    前言:本文是基于虚拟机上的centOS 7对Nginx的安装,可以使用 uname -a查看centOS系统版本,本文用来记录安装nginx的步骤和相关命令,方便日后使用时查看。 …

    Java 2023年6月5日
    078
  • getSessionFactory().openSession()导致druid连接池中的连接都占用满但无法回收

    该问题产生的现象 页面刷新几次后,就卡住,线上就得需要重新部署(还好是测试环境,不是真正生产环境) 过程及原因 查看日志线程池满了 Caused by: org.springfra…

    Java 2023年6月7日
    069
  • Centos7安装Docker

    0.安装Docker Docker 分为 CE 和 EE 两大版本。CE 即社区版(免费,支持周期 7 个月),EE 即企业版,强调安全,付费使用,支持周期 24 个月。 Dock…

    Java 2023年6月13日
    074
  • Spring Cloud Consul 实现服务注册和发现

    Spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具,它为基于 JVM 的云应用开发中涉及的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全…

    Java 2023年5月30日
    071
  • Java Thread的interrupt详解

    一、概述:1、没有任何语言方面的需求一个被中断的线程应该终止。中断一个线程只是为了引起该线程的注意,被中断线程可以决定如何应对中断。 2、Thread.interrupt()方法不…

    Java 2023年5月29日
    066
  • OO第四单元&课程总总结

    OO第四单元&课程总总结 时刻提醒自己不能跑题完结撒花 OO第四单元&课程总总结 架构介绍 + 类图 顺序图 状态图 关于算法 设计思维 与 OO理解演进 封装与解…

    Java 2023年6月13日
    070
  • 客观的聊一聊,裁员这件糟心事

    时间在走,环境在变,互联网有点卷不动了; 捋一捋最近互联网上关于职场的热点:裁员,优化,毕业,向社会输送人才,求职;你方唱罢他方登场,持续横跳热搜; 年初到现在五月底,身边已经有好…

    Java 2023年6月15日
    082
  • 什么是vpn?为什么要使用vpn?

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年6月13日
    069
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球