当前位置 博文首页 > java设计模式-抽象工厂模式

    java设计模式-抽象工厂模式

    作者:燕雀安知毛驴之志 时间:2021-01-09 12:01

    抽象工厂模式详解

     一,概述

      抽象工厂模式为一个产品家族提供了统一的创建接口。当需要这个产品家族的某一系列的时候,可以从抽象工厂中选出相对应的系列来创建一个具体的工厂类别。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

      在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

      相关术语:

    • 产品等级结构:产品的继承结构,与类的继承相似。例如笔记本是一个抽象的类,那么华为笔记本、苹果和联想笔记本就是其子类。

    • 产品族:指同一个工厂生产的,位于不同的产品等级结构的一组产品。例如华为笔记本、手机、路由器等都产自华为,笔记本的等级结构不同,构成一个产品族。

    • 抽象工厂:是一个接口,抽象工厂模式的核心,包含对多个产品等级结构的声明,任何工厂类都必须实现这个接口。

    • 具体工厂:是抽象工厂的实现,负责实例化某个产品族中的产品对象。例如华为工厂生产华为笔记本、手机、路由器等。

    二,产品族和产品等级结构图

      我们以一个品牌为一个产品族,电脑、手机、路由器为产品等级,每一个品牌都有自己的产品族,这就构成一个完整产品群;

      横向代表一族,纵向代表一个等级,横纵交集代表某一个品牌的某一个产品(比如下图中交集的点为电脑),请看下图;

      

     三,UML图

      这个类图其实比较简单,简单说明下:

      产品顶级接口:主要被产品抽象类实现;

      产品抽象类:某个具体产品要实现的类;

      具体实现类:具体产品实现,比如华为路由器实现自抽象类AbstractRouter;

      工厂接口:工厂接口中定义创建每个产品方法;

      具体华为工厂:实现工厂接口,创建华为一族产品(路由器、手机、电脑);

      

     四,具体代码实现

      代码中我们以华为产品为例,分别定义华为电脑、手机、路由器产品,从UML类图中可以看出我们的产品结构层级比较清晰,现在我们先设计我们产品。

      下面开始定义产品;

      产品顶级接口;

    package pattern.abstractfactory.product;
    /**
     * 定义产品接口
     * @author ningbeibei
     */
    public interface InterfaceProduct {
        void get();
    }

      定义计算机抽象类并实现产品InterfaceProduct 接口;

    package pattern.abstractfactory.product;
    /**
     * 定义计算机产品抽象类,并实现产品接口InterfaceProduct
     * @author ningbeibei
     */
    public abstract class AbstractComputers implements InterfaceProduct {
        public abstract void get();
    }

      定义手机抽象类并实现产品InterfaceProduct 接口;

    package pattern.abstractfactory.product;
    /**
     * 定义手机抽象类,并实现产品接口InterfaceProduct
     * @author ningbeibei
     */
    public abstract class AbstractPhone  implements InterfaceProduct {
        public abstract void get();
    }

      定义路由器抽象类并实现产品InterfaceProduct 接口;

    package pattern.abstractfactory.product;
    /**
     * 定义路由器产品抽象类,并实现InterfaceProduct接口
     * @author ningbeibei
     */
    public abstract class AbstractRouter implements InterfaceProduct{
        public abstract void get();
    }

      定义华为电脑具体实现类,继承AbstractComputers抽象类;

    package pattern.abstractfactory.product;
    /**
      * 华为电脑实现类
     * @author ningbeibei
     */
    public class HuaWeiComputer extends AbstractComputers{
        @Override
        public void get() {
            System.out.println("华为笔记本");
        }
    }

      定义华为手机具体实现类,继承AbstractPhone抽象类;

    package pattern.abstractfactory.product;
    /**
      *  华为手机实现类,
     * @author ningbeibei
     */
    public class HuaWeiPhone extends AbstractPhone{
        @Override
        public void get() {
            System.out.println("华为手机");
        }
    }

      定义华为路由器具体实现类,继承AbstractRouter抽象类;

    package pattern.abstractfactory.product;
    /**
     * 华为路由器
     * @author ningbeibei
     */
    public class HuaWeiRouter extends AbstractRouter {
        @Override
        public void get() {
            System.out.println("华为品牌路由器");
        }
    }

      下面开始定义工厂;

      定义工厂接口;

    package pattern.abstractfactory.factory;
    import pattern.abstractfactory.product.InterfaceProduct;
    /**
     * 定义产品工厂接口,
     * @author ningbeibei
     */
    public interface InterfactFactory {
        //手机产品
        InterfaceProduct createPhone();
        //电脑产品
        InterfaceProduct createComputer();
        //路由器产品
        InterfaceProduct createRouter();
    }

      具体工厂实现类,实现 InterfactFactory  接口;

    package pattern.abstractfactory.factory;
    import pattern.abstractfactory.product.HuaWeiComputer;
    import pattern.abstractfactory.product.HuaWeiPhone;
    import pattern.abstractfactory.product.HuaWeiRouter;
    import pattern.abstractfactory.product.InterfaceProduct;
    /**
     * 华为工厂
     * @author ningbeibei
     */
    public class HuaWeiFactory implements InterfactFactory {
        /**
         * 创建电脑对象并返回
         */
        @Override
        public InterfaceProduct createComputer() {
            return new HuaWeiComputer();
        }
        /**
         * 创建手机对象并返回
         */
        @Override
        public InterfaceProduct createPhone() {
            return new HuaWeiPhone();
        }
        /**
         * 创建路由器对象并返回
         */
        @Override
        public InterfaceProduct createRouter() {
            return new HuaWeiRouter();
        }
    }

      测试类;

    package pattern.abstractfactory;
    import pattern.abstractfactory.factory.HuaWeiFactory;
    import pattern.abstractfactory.factory.InterfactFactory;
    import pattern.abstractfactory.product.InterfaceProduct;
    /**
     * 抽象工厂模式测试类
     * @author ningbeibei
     */
    public class test {
        public static void main(String[] args) {
            //创建华为品牌工厂
            InterfactFactory huawei = new HuaWeiFactory();
            //通过华为工厂获取华为电脑对象
            InterfaceProduct computer = huawei.createComputer();
            computer.get();
            //通过华为工厂获取华为手机对象
            InterfaceProduct phone = huawei.createPhone();
            phone.get();
            //通过华为工厂获取华为路由器对象
            InterfaceProduct router = huawei.createRouter();
            router.get();
        }
    }

      运行结果;

    五,抽象工厂方法模式如何扩展产品族

      抽象工厂模式对于横向扩展方便,对于纵向扩展非常困难也就是说:假如我们要扩展一个新的品牌,比如扩展一个小米品牌,小米产品有电脑、手机、路由器,扩展新品牌就是横向扩展,非常方便,但是我们要给小米添加一个电饭煲产品却非常困难,这就是纵向扩展,所以在使用抽象工厂模式时一定要选择合适的场景,也就是在不同场景中使用最适合的模式才是设计模式的精髓。

      下面我们就来横向扩展一个新品牌的产品族,需要添加电脑、手机、路由器具体类(小米品牌)代码如下;

      小米电脑

    package pattern.abstractfactory.product;
    /**
     * 小米电脑,继承自 AbstractComputers 抽象类
     * @author ningbeibei
     */
    public class MiComputer extends AbstractComputers {
        @Override
        public void get() {
            System.out.println("小米电脑");
        }
    }

      小米手机

    package pattern.abstractfactory.product;
    /**
     * 小米手机,继承自 AbstractPhone 抽象类
     * @author ningbeibei
     */
    public class MiPhone extends AbstractPhone {
        @Override
        public void get() {
            System.out.println("小米手机");
        }
    }

      小米路由器

    package pattern.abstractfactory.product;
    /**
      * 小米路由器,继承自 AbstractRouter 抽象类
     * @author ningbeibei
     */
    public class MiRouter extends AbstractRouter{
        @Override
        public void get() {
            System.out.println("小米路由器");
        }
    }

      添加小米具体工厂类

    package pattern.abstractfactory.factory;
    import pattern.abstractfactory.product.InterfaceProduct;
    import pattern.abstractfactory.product.MiComputer;
    import pattern.abstractfactory.product.MiPhone;
    import pattern.abstractfactory.product.MiRouter;
    /**
     * 小米工厂,实现 InterfactFactory 接口
     * @author ningbeibei
     */
    public class MiFactory implements InterfactFactory{
        //小米手机
        @Override
        public InterfaceProduct createPhone() {
            return new MiPhone();
        }
        //小米电脑
        @Override
        public InterfaceProduct createComputer() {
            return new MiComputer();
        }
        //小米路由器
        @Override
        public InterfaceProduct createRouter() {
            return new MiRouter();
        }
    }

      最后编写测试类,代码中红色字体为新扩展的品牌产品

    package pattern.abstractfactory;
    import pattern.abstractfactory.factory.HuaWeiFactory;
    import pattern.abstractfactory.factory.InterfactFactory;
    import pattern.abstractfactory.factory.MiFactory;
    import pattern.abstractfactory.product.InterfaceProduct;
    /**
     * 抽象工厂模式测试类
     * @author ningbeibei
     */
    public class test {
        public static void main(String[] args) {
            // 创建华为品牌工厂
            InterfactFactory huawei = new HuaWeiFactory();
            // 通过华为工厂获取华为电脑对象
            InterfaceProduct computer = huawei.createComputer();
            computer.get();
            // 通过华为工厂获取华为手机对象
            InterfaceProduct phone = huawei.createPhone();
            phone.get();
            // 通过华为工厂获取华为路由器对象
            InterfaceProduct router = huawei.createRouter();
            router.get();
    
            // 创建小米品牌工厂
            InterfactFactory Mifactory = new MiFactory();
            // 通过小米工厂获取小米电脑对象
            InterfaceProduct micomputer = Mifactory.createComputer();
            micomputer.get();
            // 通过小米工厂获取小米手机对象
            InterfaceProduct miphone = Mifactory.createPhone();
            miphone.get();
            // 通过小米工厂获取小米路由器对象
            InterfaceProduct mirouter = Mifactory.createRouter();
            mirouter.get();
        }
    }

      运行结果:

     

      注意:通过上面的品牌扩展我们发现,横向扩展容易,纵向扩展非常困难,代码可以非常方便的扩展一个品牌已有的产品,但要扩展一个未定义的产品却异常困难,比如要扩展一个华为平板,需要修改工厂逻辑代码,新增产品结构,这显然不符合设计模式开闭原则,所以在使用时一定要考虑清楚,确定不在有新的产品等级扩展。

    六,优点和缺点及使用场景

    优点

    • 抽象工厂模式隔离了具体类的生成, 使得客户并不需要知道什么被创建。 由于这种隔离,更换一个具体工厂就变得相对容易, 所有的具体工厂都实现了抽象工厂中定义的那些公共接口, 因此只需改变具体工厂的实例, 就可以在某种程度上改变整个软件系统的行为。

    • 当一个族中的多个对象被设计成一起工作时, 它能够保证客户端始终只使用同一个族中的对象。

    • 增加新的族很方便, 无须修改已有系统, 符合“开闭原则”。

    缺点

    • 增加新的等级结构麻烦, 需要对原有系统进行较大的修改, 甚至需要修改抽象层代码,这显然会带来较大的不便, 违背了“开闭原则”。

    使用场景

    • 一个系统不应当依赖于具体类实例如何被创建、 组合和表达的细节, 这对于所有类型的工厂模式都是很重要的, 用户无须关心对象的创建过程, 将对象的创建和使用解耦。

    • 系统中有多于一个的族, 而每次只使用其中某一族。 可以通过配置文件等方式来使得用户可以动态改变族, 也可以很方便地增加新的族。

    • 等级结构稳定, 设计完成之后, 不会向系统中增加新的等级结构或者删除已有的等级结构。