8种常用的设计模式(5) —— 抽象工厂模式

1.什么是抽象工厂模式

  • 注意:抽象工厂模式不属于工厂模式,抽象工厂模式和工厂模式是两中设计模式
  • 定义∶抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类
  • 适用场景:
    • 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
    • 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量的重复代码
    • 提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户端不依赖于具体的实现
  • 优点:
    • 具体产品在应用层的代码隔离,无需关心创建的细节
    • 将一个系列的产品统一到一起创建
  • 缺点:
    • 规定了所有可能被创建的产品集合,产品簇中扩展新的产品困难;
    • 增加了系统的抽象性和理解难度

在这里插入图片描述

  • 产品族和产品等级
    在这里插入图片描述
  • 产品等级:就是由不同的工厂/厂商生产出的相同性值的产品;比如:上图中的小米和华为手机,都是手机,但是是从两个不同的工厂中生产的相同性值(手机)的产品
  • 产品族:就是由一个工厂/厂商生产的,不同性值的产品;比如:上图中的小米手机和小米路由器,都是从一个工厂中生产出来的,但是是不同的产品性值(一个是手机,一个是路由器)
  • 区分这两个概念的原因是因为抽象工厂模式是围绕产品族进行生产的,即抽象工厂模式生产的是一个可以创建一个产品族的产品的工厂/厂商,可以简单理解为创建了一家公司

2.代码实现

  • 创建两个接口类:PhoneProduct+RouterProduct,用于规范生产某一产品(比如:手机和路由器)的时候必须实现的功能
    public interface PhoneProduct {
        void start();//开机
        void shutdown();//关机
        void call();//打电话
        void message();//发短信
    }
    
    public interface RouterProduct {
        void start();//开机
        void shutdown();//关机
        void openWifi();//启动wifi
        void setting();//设置路由器
    }
    
  • 创建上面产品的实现类
    小米系列产品
    public class XiaomiPhone implements PhoneProduct{
        @Override
        public void start() {
            System.out.println("小米手机-开机");
        }
    
        @Override
        public void shutdown() {
            System.out.println("小米手机-关机");
        }
    
        @Override
        public void call() {
            System.out.println("小米手机-打电话");
        }
    
        @Override
        public void message() {
            System.out.println("小米手机-发短信");
        }
    }
    public class XiaomiRouter implements RouterProduct{
        @Override
        public void start() {
            System.out.println("小米路由器-开机");
        }
    
        @Override
        public void shutdown() {
            System.out.println("小米路由器-关机");
        }
    
        @Override
        public void openWifi() {
            System.out.println("小米路由器-开启WiFi");
        }
    
        @Override
        public void setting() {
            System.out.println("小米路由器-设置WiFi参数");
        }
    }
    
    =============================================================================
    华为系列产品
    public class HuaweiPhone implements PhoneProduct{
        @Override
        public void start() {
            System.out.println("华为手机-开机");
        }
    
        @Override
        public void shutdown() {
            System.out.println("华为手机-关机");
        }
    
        @Override
        public void call() {
            System.out.println("华为手机-打电话");
        }
    
        @Override
        public void message() {
            System.out.println("华为手机-发短信");
        }
    }
    public class HuaweiRouter implements RouterProduct{
        @Override
        public void start() {
            System.out.println("华为路由器-开机");
        }
    
        @Override
        public void shutdown() {
            System.out.println("华为路由器-关机");
        }
    
        @Override
        public void openWifi() {
            System.out.println("华为路由器-开启WiFi");
        }
    
        @Override
        public void setting() {
            System.out.println("华为路由器-设置WiFi参数");
        }
    }
    
  • 上面的接口就是实现了要生产的产品的约束,具体的产品类就按照接口规范实现自己的产品即可
  • 接下来就是客户端获取产品和使用产品,按照工厂设计模式的使用步骤,现在我们应该定义一个简单/静态工厂类,用于返回对应产品的实例;但是按照抽象工厂模式的原则,在创建工厂之前,我们应该创建一个工厂接口,该接口用于规范所有的工厂类
  • 比如:要实现一个工厂类,就必须要有生产手机和路由器的方法
    public interface IProductFactory {  //抽象的产品工厂,用于规范创建的工厂
        //工厂必须能够生产手机
        PhoneProduct phoneProduct();
        //工厂必须能够生产路由器
        RouterProduct routerProduct();
    }
    
  • 在上面工厂接口的基础上,我们再来根据产品族的不同,实现工厂接口
    public class XiaomiFactory implements IProductFactory{
        @Override
        public PhoneProduct phoneProduct() {
            return new XiaomiPhone();
        }
    
        @Override
        public RouterProduct routerProduct() {
            return new XiaomiRouter();
        }
    }
    ==============================================================
    public class HuaweiFactory implements IProductFactory{
        @Override
        public PhoneProduct phoneProduct() {
            return new HuaweiPhone();
        }
    
        @Override
        public RouterProduct routerProduct() {
            return new HuaweiRouter();
        }
    }
    
  • 客户端测试
    public class Client {
        public static void main(String[] args) {
            System.out.println("========小米系列产品========");
            XiaomiFactory xiaomiFactory = new XiaomiFactory();
            PhoneProduct phone1 = xiaomiFactory.phoneProduct();
            RouterProduct router1 = xiaomiFactory.routerProduct();
            System.out.println("========小米手机========");
            phone1.start();
            phone1.call();
            phone1.message();
            phone1.shutdown();
            System.out.println("========小米路由器========");
            router1.start();
            router1.openWifi();
            router1.setting();
            router1.shutdown();
    
            System.out.println("========华为系列产品========");
            HuaweiFactory HuaweiFactory = new HuaweiFactory();
            PhoneProduct phone2 = HuaweiFactory.phoneProduct();
            RouterProduct router2 = HuaweiFactory.routerProduct();
            System.out.println("========华为手机========");
            phone2.start();
            phone2.call();
            phone2.message();
            phone2.shutdown();
            System.out.println("========华为路由器========");
            router2.start();
            router2.openWifi();
            router2.setting();
            router2.shutdown();
        }
    }
    

在这里插入图片描述
在这里插入图片描述

  • 通过上面的例子我们可以看出:抽象工厂模式,就是对于工厂本身也要进行抽象,且抽象的工厂是针对产品族的抽象,所有的工厂类都要实现这个接口,所以所有的工厂类都需要生产工厂抽象中有的产品,即需要生产这个产品族中的所有产品,如果不想生产的工厂,可以直接返回null;即一个工厂中必须要生产一系列的东西,其对应获取产品实例的方法我们都应该定义在该接口中,然后我们按照一个产品族一个工厂接口实现类的标准,在工厂类中实现本产品族中具体产品的生产(就是new对象)
  • 比如上面例子中,我们定义了一个抽象接口IProductFactory,这个接口要求实现它的工厂类必须实现生产手机和路由器的方法,即一个工厂就必须要生产这两款产品,不想生产可以直接返回null,但是方法体还是要存在;当我们需要生产小米手机的时候,我们就创建了一个工厂类XiaomiFactory去实现接口IProductFactory,然后我们实现生产手机和路由器的时候,直接return new 小米手机/路由器的构造,这就实现了小米工厂产品族中产品的生产,就是实现了这两款产品的工厂类中获取对应实例的方法
  • 当客户端需要使用小米系列产品的时候,只需要new一个小米产品族工厂类,调用抽线工厂接口中的方法就可以获取到对应的产品,这就保留了原来工厂模式的优点:将产品生产和使用分离

  • 此时我们再来回顾一下抽象工厂模式的定义
    • 定义∶抽象工厂模式提供了一个创建一系列相关或者相互依赖对象(即一个产品族中的产品)的接口,无需指定它们具体的类
    • 适用场景:
      • 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节(工厂模式)
      • 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量的重复代码
      • 提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户端不依赖于具体的实现
    • 优点:
      • 具体产品在应用层的代码隔离,无需关心创建的细节
      • 将一个系列的产品统一到一起创建
    • 缺点:
      • 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难(因为一旦新增一个工厂类需要生产的产品,那么所有的工厂实现类都要新增获取这个产品的方法)
      • 增加了系统的抽象性和理解难度

3.小结

  • 抽象工厂模式和工厂模式的区别
    • 抽象工厂将注意力从产品转移到了工厂本身/产品族上,原来的工厂模式主要注意产品的生产
    • 在我们的产品族生产的产品种类比较稳定的时候,我们应该优先使用抽象工厂模式,这样使用起来更有效率;如果产品族生产的产品变化比较频繁,我们应该优先使用简单工厂模式,总之具体选取哪一个模式还是根据自己的业务需求来定的
  • 简单小结抽象工厂模式,就是生产产品的工厂的抽象,我们可以通过抽象工厂的接口实现对于工厂要生产的产品的约束

  • 简单工厂模式(静态工厂模式)

    • 虽然某种程度上不符合设计原则,但实际使用最多!
  • 工厂方法模式

    • 不修改已有类的前提下,通过增加新的工厂类实现扩展
  • 抽象工厂模式

    • 不可以增加产品,可以增加产品族,是工厂的抽象
  • 应用场景:

    • JDK中Calendar的getInstance方法
    • JDBC中的Connection对象的获取
    • Spring中IOC容器创建管理bean对象
    • 反射中Class对象的newInstance方法
此资源出自下面的作者,我只是转载,非常实用的设计方法,如果您想成位出色的设计师,那就再复习复习吧!如果您想成为软件设计师,通过学习,您将会站另一个高度看待软件设计. 原始地址:http://terrylee.cnblogs.com/archive/2005/12/13/295965.html ========================================= 抽象工厂模式(Abstract Factory) ——探索设计模式系列之三 Terrylee,2005年12月12日 概述 在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时由于需求的变化,往往存在着更多系列对象的创建工作。如何应对这变化?如何绕过常规的对象的创建方法(new),提供一“封装机制”来避免客户程序和这“多系列具体对象创建工作”的紧耦合?这就是我们要说的抽象工厂模式。 意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 模型图 逻辑模型: 物理模型: 生活中的例子 抽象工厂的目的是要提供一个创建一系列相关或相互依赖对象的接口,而不需要指定它们具体的类。这模式可以汽车制造厂所使用的金属冲压设备中找到。这冲压设备可以制造汽车车身部件。同样的机械用于冲压不同的车型的右边车门、左边车门、右前挡泥板、左前挡泥板和引擎罩等等。通过使用转轮来改变冲压盘,这个机械产生的具体类可以在三分钟内改变。 抽象工厂之新解 虚拟案例 中国企业需要一项简单的财务计算:每月月底,财务人员要计算员工的工资。 员工的工资 = (基本工资 + 奖金 - 个人所得税)。这是一个放之四海皆准的运算法则。 为了简化系统,我们假设员工基本工资总是4000美金。 中国企业奖金和个人所得税的计算规则是: 奖金 = 基本工资(4000) * 10% 个人所得税 = (基本工资 + 奖金) * 40% 我们现在要为此构建一个软件系统(代号叫Softo),满足中国企业的需求。 案例分析 奖金(Bonus)、个人所得税(Tax)的计算是Softo系统的业务规则(Service)。 工资的计算(Calculator)则调用业务规则(Service)来计算员工的实际工资。 工资的计算作为业务规则的前端(或者客户端Client)将提供给最终使用该系统的用户(财务人员)使用。 针对中国企业为系统建模 根据上面的分析,为Softo系统建模如下: 则业务规则Service类的代码如下: ......
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值