精华内容
下载资源
问答
  • 如果要扩大后花园的规模,比如一个在北方,一个在南方,这样工厂方法就无法实现了,就应当用抽象工厂,把各种各样的植物,又组成一个后花园. 所以我个人认为,简单工厂是一个工厂只生产一类的产品,面对的是具体的类,工厂...
  • 4.简单工厂-工厂方法-抽象工厂 对比总结
  • 介绍的是工厂模式 包括简单工厂模式、工厂方法模式、抽象工厂模式 包括PPT和代码
  • java 三种工厂模式(简单工厂+工厂方法+抽象工厂)

    万次阅读 多人点赞 2019-06-04 10:51:15
    因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法模式,它属于类创建型模式。 工厂模式结构图 简单工厂模式角色   在简单工厂模式结构图中包含如下几个角色: ...

    一、简单工厂模式

    概述

      简单工厂模式:定义一个工厂类,它可以根据参数的不同返回不同类的 实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法模式,它属于类创建型模式。
    工厂模式结构图

    工厂模式结构图
    简单工厂模式角色

      在简单工厂模式结构图中包含如下几个角色:

    • Factory(工厂角色):工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它的返回类型为抽象产品类型Product。
    • Product(抽象产品角色):它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
    • ConcreteProduct(具体产品角色):它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。
    案例

      Sunny软件公司欲基于Java语言开发一套图表库,该图表库可以为应用系统提供各种不同外观的图表,例如柱状图、饼状图、折线图等。Sunny软件公司图表库设计人员希望为应用系统开发人员提供一套灵活易用的图表库,而且可以较为方便地对图表库进行扩展,以便能够在将来增加一些新类型的图表。
      Sunny软件公司图表库设计人员提出了一个初始设计方案,将所有图表的实现代码封装在一个Chart类中,其框架代码如下所示:

    class Chart {
        private String type;    //图表类型
        public Chart(Object[][] data, String type) {
            this.type = type;
            if (type.equalsIgnoreCase("histogram")) {
                //初始化柱状图
            } else if (type.equalsIgnoreCase("pie")) {
                //初始化饼状图
            } else if (type.equalsIgnoreCase("line")) {
                //初始化折线图
            }
        }
        public void display() {
            if (this.type.equalsIgnoreCase("histogram")) {
                //显示柱状图
            } else if (this.type.equalsIgnoreCase("pie")) {
                //显示饼状图
            } else if (this.type.equalsIgnoreCase("line")) {
                //显示折线图
            }
        }
    }
    

      客户端代码通过调用Chart类的构造函数来创建图表对象,根据参数type的不同可以得到不同类型的图表,然后再调用display()方法来显示相应的图表。
      不难看出,Chart类是一个“巨大的”类,在该类的设计中存在如下几个问题:

    1. 在Chart类中包含很多“if…else…”代码块,整个类的代码相当冗长,代码越长,阅读难度、维护难度和测试难度也越大;而且大量条件语句的存在还将影响系统的性能,程序在执行过程中需要做大量的条件判断。
    2. Chart类的职责过重,它负责初始化和显示所有的图表对象,将各种图表对象的初始化代码和显示代码集中在一个类中实现,违反了“单一职责原则”,不利于类的重用和维护;而且将大量的对象初始化代码都写在构造函数中将导致构造函数非常庞大,对象在创建时需要进行条件判断,降低了对象创建的效率。
    3. 当需要增加新类型的图表,必须修改Chart类的源代码,违反了“开闭原则”。
    4. 客户端只能通过new关键字来直接创建Chart对象,Chart类与客户端类耦合度较高,对象的创建和使用无法分离。
    5. 客户端在创建Chart对象之前可能还需要进行大量初始化设置,例如设置柱状图的颜色、高度等,如果在Chart类的构造函数中没有提供一个默认设置,那就只能由客户端来完成初始设置,这些代码在每次创建Chart对象时都会出现,导致代码的重复。
    完整解决方案

      为了将Chart类的职责分离,同时将Chart对象的创建和使用分离,Sunny软件公司开发人员决定使用简单工厂模式对图表库进行重构,重构后的结构如下图所示:
    在这里插入图片描述
      从图上我们可以看出,Chart接口充当抽象产品类,其子类HistogramChart、PieChart和LineChart充当具体产品类,ChartFactory充当工厂类。完整代码如下所示:

    //抽象图表接口:抽象产品类
    interface Chart {
        public void display();
    }
    //柱状图类:具体产品类
    class HistogramChart implements Chart {
        public HistogramChart() {
            System.out.println("创建柱状图!");
        }
        public void display() {
            System.out.println("显示柱状图!");
        }
    }
    //饼状图类:具体产品类
    class PieChart implements Chart {
        public PieChart() {
            System.out.println("创建饼状图!");
        }
        public void display() {
            System.out.println("显示饼状图!");
        }
    }
    //折线图类:具体产品类
    class LineChart implements Chart {
        public LineChart() {
            System.out.println("创建折线图!");
        }
        public void display() {
            System.out.println("显示折线图!");
        }
    }
    //图表工厂类:工厂类
    class ChartFactory {
        //静态工厂方法
        public static Chart getChart(String type) {
            Chart chart = null;
            if (type.equalsIgnoreCase("histogram")) {
                chart = new HistogramChart();
                System.out.println("初始化设置柱状图!");
            } else if (type.equalsIgnoreCase("pie")) {
                chart = new PieChart();
                System.out.println("初始化设置饼状图!");
            } else if (type.equalsIgnoreCase("line")) {
                chart = new LineChart();
                System.out.println("初始化设置折线图!");
            }
            return chart;
        }
    }
    //编写如下客户端测试代码:
    class Client {
        public static void main(String args[]) {
            Chart chart;
            chart = ChartFactory.getChart("histogram"); //通过静态工厂方法创建产品
            chart.display();
        }
    }
    
    简单工厂模式的简化

      有时候,为了简化简单工厂模式,我们可以将抽象产品类和工厂类合并,将静态工厂方法移至抽象产品类中,如下图所示。
    在这里插入图片描述

    总结
    1. 主要优点:
    • 工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离。
    • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可。
    • 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
    1. 主要缺点:
    • 由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响。
    • 使用简单工厂模式势必会增加系统中类的个数(引入了新的工厂类),增加了系统的复杂 度和理解难度。
    • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成 工厂逻辑过于复杂,不利于系统的扩展和维护。
    • 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
    1. 适用场景
    • 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
    • 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。

    二、工厂方法模式

    工厂方法模式概述

      在简单工厂模式中只提供一个工厂类,该工厂类处于对产品类进行实例化的中心位置,它需要知道每一个产品对象的创建细节,并决定何时实例化哪一个产品类。简单工厂模式最大的缺点是当有新产品要加入到系统中时,必须修改工厂类,需要在其中加入必要的业务逻辑,这违背了“开闭原则”。此外,在简单工厂模式中,所有的产品都由同一个工厂创建,工厂类职责较重,业务逻辑较为复杂,具体产品与工厂类之间的耦合度高,严重影响了系统的灵活性和扩展性,而工厂方法模式则可以很好地解决这一问题。
      在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构。
      工厂方法模式:定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式,又可称作虚拟构造器模式或多态工厂模式。工厂方法模式是一种类创建型模式。
      工厂方法模式提供一个抽象工厂接口来声明抽象工厂方法,而由其子类来具体实现工厂方法,创建具体的产品对象。工厂方法模式结构如图所示:
    在这里插入图片描述

    工厂方法模式角色
    • Product(抽象产品):它是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类。
    • ConcreteProduct(具体产品):它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应。
    • Factory(抽象工厂):在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。
    • ConcreteFactory(具体工厂):它是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户端调用,返回一个具体产品类的实例。

      与简单工厂模式相比,工厂方法模式最重要的区别是引入了抽象工厂角色,抽象工厂可以是接口,也可以是抽象类或者具体类,其典型代码如下所示:

    interface Factory {
        public Product factoryMethod();	
    }
    

      在抽象工厂中声明了工厂方法但并未实现工厂方法,具体产品对象的创建由其子类负责,客户端针对抽象工厂编程,可在运行时再指定具体工厂类,具体工厂类实现了工厂方法,不同的具体工厂可以创建不同的具体产品,其典型代码如下所示:

    class ConcreteFactory implements Factory {
        public Product factoryMethod() {
            return new ConcreteProduct();
        }
    }
    

      在实际使用时,具体工厂类在实现工厂方法时除了创建具体产品对象之外,还可以负责产品对象的初始化工作以及一些资源和环境配置工作,例如连接数据库、创建文件等。
      在客户端代码中,只需关心工厂类即可,不同的具体工厂可以创建不同的产品,典型的客户端类代码片段如下所示:

    Factory	factory;
    factory	= new ConcreteFactory(); //可通过配置文件实现
    Product	product;
    product	= factory.factoryMethod();
    

      可以通过配置文件来存储具体工厂类ConcreteFactory的类名,更换新的具体工厂时无须修改源 代码,系统扩展更为方便。

    案例

      Sunny软件公司欲开发一个系统运行日志记录器(Logger),该记录器可以通过多种途径保存系 统的运行日志,如通过文件记录或数据库记录,用户可以通过修改配置文件灵活地更换日志记录方式。在设计各类日志记录器时,Sunny公司的开发人员发现需要对日志记录器进行一些初始化工作,初始化参数的设置过程较为复杂,而且某些参数的设置有严格的先后次序,否则可能会发生记录失败。如何封装记录器的初始化过程并保证多种记录器切换的灵活性是Sunny公司开发人员面临的一个难题。
      Sunny公司的开发人员通过对该需求进行分析,发现该日志记录器有两个设计要点:

    1. 需要封装日志记录器的初始化过程,这些初始化工作较为复杂,例如需要初始化其他相关的类,还有可能需要读取配置文件(例如连接数据库或创建文件),导致代码较长,如果将它们都写在构造函数中,会导致构造函数庞大,不利于代码的修改和维护;
    2. 用户可能需要更换日志记录方式,在客户端代码中需要提供一种灵活的方式来选择日志记录器,尽量在不修改源代码的基础上更换或者增加日志记录方式。
    class LoggerFactory {
        //静态工厂方法
        public static Logger createLogger(String args) {
            if (args.equalsIgnoreCase("db")) {
                // 连接数据库,
                // 代码省略
                // 创建数据库日志记录器对象 Logger
                logger = new DatabaseLogger();
                // 初始化数据库日志记录器,代码省略 
                return logger;
            } else if (args.equalsIgnoreCase("file")) {
                // 创建日志文件
                //创建文件日志记录器对象
                Logger logger = new FileLogger();
                //初始化文件日志记录器,代码省略		
                return logger;
            } else {
                return null;
            }
        }
    }
    

    从代码可以看出,使用简单工厂模式虽然实现了了对象的创建和使用分离,但是任然存在两个问题,1、工厂类过于庞大,导致维护和测试难度增大。2、系统扩展不灵活,如果增加新类型的日志记录器,必须修改静态工厂方法的业务逻辑,违反了“开闭原则”。

    完整解决方案

    ![](2019-06-03-18-01-56.png在这里插入图片描述
    如上图所示,Logger接口充当抽象产品,其子类FileLogger和DatabaseLogger充当具体产品,LoggerFactory接口充当抽象工厂,其子类FileLoggerFactory和DatabaseLoggerFactory充当具体工厂。完整代码如下:

    //日志记录器接口:抽象产品
    interface Logger {
        public void writeLog();
    }
    //数据库日志记录器:具体产品
    class DatabaseLogger implements Logger {
        public void writeLog() {
            System.out.println("数据库日志记录。");
        }
    }
    //文件日志记录器:具体产品
    class FileLogger implements Logger {
        public void writeLog() {
            System.out.println("文件日志记录。");
        }
    }
    //日志记录器工厂接口:抽象工厂
    interface LoggerFactory {
        public Logger createLogger();
    }
    //数据库日志记录器工厂类:具体工厂
    class DatabaseLoggerFactory implements LoggerFactory {
        public Logger createLogger() {
            //连接数据库,代码省略														
            // 创建数据库日志记录器对象
            Logger logger = new DatabaseLogger();
            //初始化数据库日志记录器,代码省略		
            return logger;
        }
    }
    //文件日志记录器工厂类:具体工厂		
    class FileLoggerFactory implements LoggerFactory {
        public Logger createLogger() {
            //创建文件日志记录器对象										
            Logger logger = new FileLogger();
            // 创建文件,代码省略												
            return logger;
        }
    }
    //编写如下客户端测试代码:
    class Client {
        public static void main(String args[]) {
            LoggerFactory factory;
            Logger logger;
            factory = new FileLoggerFactory();  //可引入配置文件实现		
            logger = factory.createLogger();
            logger.writeLog();
        }
    }
    
    工厂方法模式总结

    工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时还弥补了简单工厂模式的不足。工厂方法模式是使用频率最高的设计模式之一,是很多开源框架和API类库的 核心模式。

    1. 主要优点
    • 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
    • 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,就正是因为所有的具体工厂类都具有同一抽象父类。
    • 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
    1. 主要缺点
    • 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
    • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
    1. 适用场景
    • 客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建,可将具体工厂类的类名存储在配置文件或数据库中。
    • 抽象工厂类通过其子类来指定创建哪个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

    抽象工厂模式

    抽象工厂模式概述

      抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品。
      抽象工厂模式定义如下:抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。
      在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法用于产生多种不同类型的产品,这些产品构成了一个产品族,抽象工厂模式结构如下图所示:
    ![](2019-06-04-09-31-46.png在这里插入图片描述

    抽象工厂角色
    • AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
    • ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
    • AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
    • ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
    案例

      Sunny软件公司欲开发一套界面皮肤库,可以对Java桌面软件进行界面美化。为了保护版权,该皮肤库源代码不打算公开,而只向用户提供已打包为jar文件的class字节码文件。用户在使用时可以通过菜单来选择皮肤,不同的皮肤将提供视觉效果不同的按钮、文本框、组合框等界面元素,其结构示意图如下图所示:
    ![](2019-06-04-09-39-35.png在这里插入图片描述
      该皮肤库需要具备良好的灵活性和可扩展性,用户可以自由选择不同的皮肤,开发人员可以在不修改既有代码的基础上增加新的皮肤。
      Sunny软件公司的开发人员针对上述要求,决定使用工厂方法模式进行系统的设计,为了保证系统的灵活性和可扩展性,提供一系列具体工厂来创建按钮、文本框、组合框等界面元素,客户端针对抽象工厂编程,初始结构如下图所示:
    ![](2019-06-04-09-41-33.png在这里插入图片描述
    从上图可以发现,提供了大量工厂来创建具体的界面组件,可以通过配置文件更换具体界面组件从而改变界面风格。但是,此设计方案存在如下问题:

    1. 当需要增加新的皮肤时,虽然不要修改现有代码,但是需要增加大量类,针对每一个新增具体组件都需要增加一个具体工厂,类的个数成对增加,这无疑会导致系统越来越庞大,增加系统的维护成本和运行开销;
    2. 由于同一种风格的具体界面组件通常要一起显示,因此需要为每个组件都选择一个具体工厂,用户在使用时必须逐个进行设置,如果某个具体工厂选择失误将会导致界面显示混乱,虽然我们可以适当增加一些约束语句,但客户端代码和配置文件都较为复杂。
    产品等级结构与产品族

      在介绍完整解决方案之前,为了更好地理解抽象工厂模式,我们先引入两个概念。在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法具有唯一性,一般情况下,一个具体工厂中只有一个或者一组重载的工厂方法。但是有时候我们希望一个工厂可以提供多个产品对象,而不是单一的产品对象,如一个电器工厂,它可以生产电视机、电冰箱、空调等多种电器,而不是只生产某一种电器。

    1. 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
    2. 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。产品等级结构与产品族示意图如图所示:
      ![](2019-06-04-09-48-42.png在这里插入图片描述
        在上图中,不同颜色的多个正方形、圆形和椭圆形分别构成了三个不同的产品等级结构,而相同颜色的正方形、圆形和椭圆形构成了一个产品族,每一个形状对象都位于某个产品族,并属于某个产品等级结构。图中一共有五个产品族,分属于三个不同的产品等级结构。我们只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一确定这个产品。
        当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。抽象工厂模式与工厂方法模式最大的区别在于, 工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、更有效率。抽象工厂模式示意图如图所示:
      ![](2019-06-04-09-51-46.png在这里插入图片描述
        在图中,每一个具体工厂可以生产属于一个产品族的所有产品,例如生产颜色相同的正方形、圆形和椭圆形,所生产的产品又位于不同的产品等级结构中。如果使用工厂方法模式,需要提供15个具体工厂,而使用抽象工厂模式只需要提供5个具体工厂,极大减少了系统中类的个数。
    完整解决方案

      Sunny公司开发人员使用抽象工厂模式来重构界面皮肤库的设计,其基本结构如图所示:
    ![](2019-06-04-09-54-08.png在这里插入图片描述
    在图中,SkinFactory接口充当抽象工厂,其子类SpringSkinFactory和SummerSkinFactory充当 具体工厂,接口Button、TextField和ComboBox充当抽象产品,其子类SpringButton、SpringTextField、SpringComboBox和SummerButton、SummerTextField、SummerComboBox充当具体产品。完整代码如下所示:

    //在本实例中我们对代码进行了大量简化,实际使用时,界面组件的初始化代码较为复杂,还需要使用JD 
    //按钮接口:抽象产品
    interface Button {
        public void display();
    }
    //Spring按钮类:具体产品
    class SpringButton implements Button {
        public void display() {
            System.out.println("显示浅绿色按钮。");
        }
    }
    //Summer按钮类:具体产品
    class SummerButton implements Button {
        public void display() {
            System.out.println("显示浅蓝色按钮。");
        }
    }
    //文本框接口:抽象产品
    interface TextField {
        public void display();
    }
    //Spring文本框类:具体产品
    class SpringTextField implements TextField {
        public void display() {
            System.out.println("显示绿色边框文本框。");
        }
    }
    //Summer文本框类:具体产品
    class SummerTextField implements TextField {
        public void display() {
            System.out.println("显示蓝色边框文本框。");
        }
    }
    //组合框接口:抽象产品
    interface ComboBox {
        public void display();
    }
    //Spring组合框类:具体产品
    class SpringComboBox implements ComboBox {
        public void display() {
            System.out.println("显示绿色边框组合框。");
        }
    }
    //Summer组合框类:具体产品
    class SummerComboBox implements ComboBox {
        public void display() {
            System.out.println("显示蓝色边框组合框。");
        }
    }
    //界面皮肤工厂接口:抽象工厂
    interface SkinFactory {
        public Button createButton();
        public TextField createTextField();
        public ComboBox createComboBox();
    }
    //Spring皮肤工厂:具体工厂
    class SpringSkinFactory implements SkinFactory {
        public Button createButton() {
            return new SpringButton();
        }
        public TextField createTextField() {
            return new SpringTextField();
        }
        public ComboBox createComboBox() {
            return new SpringComboBox();
        }
    }
    //Summer皮肤工厂:具体工厂
    class SummerSkinFactory implements SkinFactory {
        public Button createButton() {
            return new SummerButton();
        }
        public TextField createTextField() {
            return new SummerTextField();
        }
        public ComboBox createComboBox() {
            return new SummerComboBox();
        }
    }
    //为了让系统具备良好的灵活性和可扩展性,我们引入了工具类XMLUtil和配置文件,其中, XMLUtil类的代码如下所示:
    public class XMLUtil {
        //该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
        public static Object getBean() {
            try {
                //创建文档对象
                DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstan
                DocumentBuilder builder = dFactory.newDocumentBuilder();
                Document doc;
                doc = builder.parse(new File("config.xml"));
                //获取包含类名的文本节点
                NodeList nl = doc.getElementsByTagName("className");
                Node classNode = nl.item(0).getFirstChild();
                String cName = classNode.getNodeValue();
                //通过类名生成实例对象并将其返回
                Class c = Class.forName(cName);
                Object obj = c.newInstance();
                return obj;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    // 配置文件config.xml中存储了具体工厂类的类名,代码如下所示:
    <?xml version="1.0"?><config><className>SpringSkinFactory</className></config>
    //编写如下客户端测试代码
    class Client {
        public static void main(String args[]) {
            //使用抽象层定义
            SkinFactory factory;
            Button bt;
            TextField tf;
            ComboBox cb;
            factory = (SkinFactory) XMLUtil.getBean();
            bt = factory.createButton();
            tf = factory.createTextField();
            cb = factory.createComboBox();
            bt.display();
            tf.display();
            cb.display();
        }
    }
    
    抽象工厂模式“开闭原则”的倾斜性

      在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为“开闭原则”的倾斜性。“开闭原则”要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的,对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:

    1. 增加产品族:对于增加新的产品族,抽象工厂模式很好地支持了“开闭原则”,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改。
    2. 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了“开闭原则”。
       正因为抽象工厂模式存在“开闭原则”的倾斜性,它以一种倾斜的方式来满足“开闭原则”,为增加新产品族提供方便,但不能为增加新产品结构提供这样的方便,因此要求设计人员在设计 之初就能够全面考虑,不会在设计完成之后向系统中增加新的产品等级结构,也不会删除已有的产品等级结构,否则将会导致系统出现较大的修改,为后续维护工作带来诸多麻烦。
    总结
    1. 主要优点:
    • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。
    • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
    • 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。
    1. 主要缺点:
    • 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。
    1. 适用场景
    • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦。
    • 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。
    • 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。同一个产品族中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束,如同一操作系统下的按钮和文本框,按钮与文本框之间没有直接关系,但它们都是属于某一操作系统的,此时具有一个共同的约束条件:操作系统的类型。
    • 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。
    展开全文
  • 设计模式之工厂方法简单工厂、抽象工厂
  • 主要介绍了Java设计模式之工厂模式,结合实例形式分析了简单工厂、工厂方法抽象工厂等相关功能、实现与使用方法,需要的朋友可以参考下
  • 抽象工厂模式的区别及优缺点及使用场景简单工厂普通简单工厂多方法简单工厂静态方法简单工厂工厂方法模式抽象工厂模式 工厂模式是java设计模式中比较简单的一个设计模式,但很多地方都用到了工厂模式,(如解析xml...

    简单工厂模式&工厂方法模式&抽象工厂模式的区别及优缺点及使用场景


    工厂模式是设计模式中比较简单的一个设计模式,但很多地方都用到了工厂模式,(如解析xml中,jdbc连接数据库等)利用好工厂模式对程序的设计很有用处。

    工厂模式在一些设计模式的书中分为简单工厂模式,工厂方法模式和抽象工厂模式三类。也有把工厂方法模式划分到抽象工厂模式的,认为工厂方法是抽象工厂模式的特例的一种,就是只有一个要实现的产品接口。
    在这里插入图片描述

    简单工厂

    普通简单工厂

    就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先看下关系图

    举个获取鼠标信息例子,我们有个例子。

    1. 创建获取鼠标信息共同接口
       public class LenoveMouse : IMouse
        {
            public string GetMouseInfo()
            {
                return "联想品牌鼠标";
            }
        }
    
    1. 联想鼠标实现类
     public string GetMouseInfo()
            {
                return "联想品牌鼠标";
            }
    

    3.惠普鼠标实现类

     public class HPMouse : IMouse
       {
           public string GetMouseInfo()
           {
               return "惠普品牌鼠标";
           }
       }
    
    1. 鼠标工厂类
      public class MouseFactory
        {
            /// <param name="type">0 代码惠普鼠标 1 代码联想鼠标</param>
            /// <returns></returns>
            public IMouse GetMouse(int type)
            {
                if (type == 0)
                {
                    return new HPMouse();
                }
                else if (type == 1)
                {
                    return new LenoveMouse();
                }
                else {
    
                    Console.WriteLine("请输入正确类型!");
                    return null;
                }
            }
        }
    
    1. 控制台调用
     class Program
        {
            static void Main(string[] args)
            {
                MouseFactory mouseFactory = new MouseFactory();
               string mouseInfo1 = mouseFactory.GetMouse(0).GetMouseInfo();
                Console.WriteLine(mouseInfo1);
               // 输出:惠普品牌鼠标
                string mouseInfo2 = mouseFactory.GetMouse(1).GetMouseInfo();
                Console.WriteLine(mouseInfo2);
               //输出:联想品牌鼠标
            }
        }
    

    多方法简单工厂

    是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的类型出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。关系图:
    在这里插入图片描述
    工厂类修改

     public class MouseFactory
        {
    
            public IMouse GetHPMouse()
            {
                return new HPMouse();
            }
    
            public IMouse GetMouse()
            {
                return new LenoveMouse();
            }
    
        }
    

    控制台调用修改

       class Program
        {
            static void Main(string[] args)
            {
                MouseFactory mouseFactory = new MouseFactory();
                string mouseInfo1 = mouseFactory.GetHPMouse().GetMouseInfo();
                //输出惠普鼠标品牌
                Console.WriteLine(mouseInfo1);          
                string mouseInfo2 = mouseFactory.GetLenoveMouse().GetMouseInfo();
                //输出联想鼠标品牌
                Console.WriteLine(mouseInfo2);
                Console.ReadLine();
            }
        }
    

    静态方法简单工厂

    将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

     public class MouseFactory
        {
    
            public static IMouse GetHPMouse()
            {
                return new HPMouse();
            }
    
            public static IMouse GetLenoveMouse()
            {
                return new LenoveMouse();
            }
    
        }
    

    控制台调用

      class Program
        {
            static void Main(string[] args)
            {          
                string mouseInfo1 = MouseFactory.GetHPMouse().GetMouseInfo();
                //输出惠普鼠标品牌
                Console.WriteLine(mouseInfo1);          
                string mouseInfo2 = MouseFactory.GetLenoveMouse().GetMouseInfo();
                //输出联想鼠标品牌
                Console.WriteLine(mouseInfo2);
                Console.ReadLine();
            }
        }
    

    工厂方法模式

    简单工厂模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改。假如增加其他品牌鼠标,工厂类需要修改,如何解决?就用到工厂方法模式,创建一个工厂接口和创建多个工厂实现类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
    在这里插入图片描述
    增加Factory接口

      public interface Factory
        {
            /// <summary>
            /// 获取鼠标工厂
            /// </summary>
            /// <returns></returns>
             IMouse GetMouseFactory();
    
        }
    

    添加惠普鼠标工厂实现类

     public class HPMouseFactory:Factory
        {
            public IMouse GetMouseFactory()
            {
                return new HPMouse();
            }
        }
    
    

    添加联想鼠标工厂实现类

    
        public class LenoveMouseFactory : Factory
        {
            public IMouse GetMouseFactory()
            {
                return new LenoveMouse();
            }
        }
    

    控制台调用

    在这里插入代码片
    
    class Program
    {
        static void Main(string[] args)
        {
            //实例化惠普鼠标工厂
            Factory factory = new HPMouseFactory();
            string mouseInfo1 = factory.GetMouseFactory().GetMouseInfo();
            //输出惠普鼠标品牌
            Console.WriteLine(mouseInfo1);
            //实例化联想鼠标工厂
            Factory factory2 = new LenoveMouseFactory();
            string mouseInfo2 = factory2.GetMouseFactory().GetMouseInfo();
            //输出联想鼠标品牌
            Console.WriteLine(mouseInfo2);
            Console.ReadLine();
        }
    }
    工厂方法模式中我们把生成产品类的时间延迟,就是通过对应的工厂类来生成对应的产品类,在这里我们就可以实现“开发-封闭”原则,无论加多少产品类,我们都不用修改原来类中的代码,而是通过增加工厂类来实现。但是这还是有缺点的,如果添加键盘产品,就需要添加键盘工厂类。假如我们要实现的产品接口不止一个,也就是有多个产品接口,不同产品接口有对应的产品族。什么是产品族呢?简单的理解就是,不同厂家的不仅有鼠标,还有键盘,音响,笔记本可以组成一个产品族。对于这种情况我们可以采用抽象工厂模式。
    

    抽象工厂模式

    最后我们新增一个键盘产品类说明抽象工厂模式
    在这里插入图片描述

    1. 创建获取鼠标信息共同接口
       public class LenoveMouse : IMouse
        {
            public string GetMouseInfo()
            {
                return "联想品牌鼠标";
            }
        }
    
    1. 联想鼠标实现类
     public string GetMouseInfo()
            {
                return "联想品牌鼠标";
            }
    

    3.惠普鼠标实现类

      public class HPMouse : IMouse
        {
            public string GetMouseInfo()
            {
                return "惠普品牌鼠标";
            }
        }
        
    

    4.创建键盘接口类

     public interface IKeyboard
        {
             string GetKeyboardInfo();    
        }
    

    5.创建惠普键盘实现类

      public class HPKeyboard : IKeyboard
        {
            public string GetKeyboardInfo()
            {
                return "惠普键盘";
            }
        }
    

    6.创建联想键盘实现类

    
        public class LenoveKeyboard : IKeyboard
        {
            public string GetKeyboardInfo()
            {
                return "联想键盘";
            }
        }
    

    7.创建工厂接口类提供获取鼠标鼠标和键盘接口

     public interface Factory
        {
            /// <summary>
            /// 获取鼠标工厂
            /// </summary>
            /// <returns></returns>
             IMouse GetMouseFactory();
            /// <summary>
            /// 获取键盘工厂
            /// </summary>
            /// <returns></returns>
            IKeyboard GetKeyboardFactory();
    
        }
    

    8.创建联想工厂实现类

      public class LenoveFactory : Factory
        {
            public IKeyboard GetKeyboardFactory()
            {
                return new LenoveKeyboard();
            }
    
            public IMouse GetMouseFactory()
            {
                return new LenoveMouse();
            }
        }
    

    9.创建惠普工厂实现类型

      public class HPFactory:Factory
        {
            public IKeyboard GetKeyboardFactory()
            {
                return new HPKeyboard();
            }
    
            public IMouse GetMouseFactory()
            {
                return new HPMouse();
            }
        }
    

    控制台调用

       class Program
        {
            static void Main(string[] args)
            {
                //实例化惠普鼠标工厂
                Factory factory = new HPFactory();
                string mouseInfo1 = factory.GetMouseFactory().GetMouseInfo();
                string keyboard1 = factory.GetKeyboardFactory().GetKeyboardInfo();
    
                //输出惠普鼠标品牌
                Console.WriteLine(mouseInfo1);
                //输出惠普键盘
                Console.WriteLine(keyboard1);
                //实例化联想鼠标工厂
                Factory factory2 = new LenoveFactory();
                string mouseInfo2 = factory2.GetMouseFactory().GetMouseInfo();
                //输出联想鼠标品牌
                Console.WriteLine(mouseInfo2);
                //输出联想键盘品牌
                string keyboard2= factory2.GetKeyboardFactory().GetKeyboardInfo();
                Console.ReadLine();
            }
        }
    

    抽象工厂模式中我们可以定义实现不止一个接口,一个工厂也可以生成不止一个产品类,抽象工厂模式较好的实现了“开放-封闭”原则,是三个模式中较为抽象,并具一般性的模式。我们在使用中要注意使用抽象工厂模式的条件。
    无论是工厂模式增加代码复制度,有没有一种办法,不需要创建工厂,也能解决代码以后变动修改少方法。答案是有的,通过(ioc)控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,(di)依赖被注入到对象中。
    后续继续讲解如何使ioc优化程序。
    案例代码下载
    由于水平有限,文章中难免有错误的地方,欢迎指出错误或不足之处,共同进步。欢迎转载,转载时请注明出处,谢谢。 ——by EricDrSun

    展开全文
  • 工厂模式将目的将创建对象的具体过程屏蔽隔离起来,从而达到更高的灵活性,工厂模式可以分为三类:简单工厂模式、工厂方法模式、抽象工厂模式;简单工厂模式的核心是定义一个创建对象的接口,将对象的创建和本身的...

            在面向对象编程中,创建对象实例最常用的方式就是通过 new 操作符构造一个对象实例,但在某些情况下,new 操作符直接生成对象会存在一些问题。举例来说,对象的创建需要一系列的步骤:可能需要计算或取得对象的初始位置、选择生成哪个子对象实例、或在生成之前必须先生成一些辅助对象。 在这些情况,新对象的建立就是一个 “过程”,而不仅仅是一个操作,就像一部大机器中的一个齿轮传动。

            针对上面这种情况,我们如何轻松方便地构造对象实例,而不必关心构造对象示例的细节和复杂过程?解决方案就是使用一个工厂类来创建对象。

    一、什么是工厂模式:

            工厂模式将目的将创建对象的具体过程屏蔽隔离起来,从而达到更高的灵活性,工厂模式可以分为三类:

    • 简单工厂模式(Simple Factory)
    • 工厂方法模式(Factory Method)
    • 抽象工厂模式(Abstract Factory)

    这三种模式从上到下逐步抽象,并且更具一般性。《设计模式》一书中将工厂模式分为两类:工厂方法模式与抽象工厂模式。将简单工厂模式看为工厂方法模式的一种特例,两者归为一类。 我们先从以下案例对工厂模式做个初步的了解:

    (1)在没有工厂的时代,如果客户需要一款宝马车,那么就需要客户去创建一款宝马车,然后拿来用。

    (2)简单工厂模式:后来出现了工厂,用户不再需要去创建宝马车,由工厂进行创建,想要什么车,直接通过工厂创建就可以了。比如想要320i系列车,工厂就创建这个系列的车。

    (3)工厂方法模式:为了满足客户,宝马车系列越来越多,如320i、523i等等系列,一个工厂无法创建所有的宝马系列,于是又单独分出来多个具体的工厂,每个具体工厂创建一种系列,即具体工厂类只能创建一个具体产品。但是宝马工厂还是个抽象,你需要指定某个具体的工厂才能生产车出来。

    (4)抽象工厂模式:随着客户要求越来越高,宝马车必须配置空调,于是这个工厂开始生产宝马车和需要的空调。最终是客户只要对宝马的销售员说:我要523i空调车,销售员就直接给他523i空调车了。而不用自己去创建523i空调车宝马车。

    下面我们就针对几种不同的工厂模式进行详细的说明:

    二、简单工厂模式:

            简单工厂模式的核心是定义一个创建对象的接口,将对象的创建和本身的业务逻辑分离,降低系统的耦合度,使得两个修改起来相对容易些,当以后实现改变时,只需要修改工厂类即可。

    如果不使用工厂,用户将自己创建宝马车,具体UML图和代码如下:

    public class BMW320 {
    	public BMW320(){
    		System.out.println("制造-->BMW320");
    	}
    }
     
    public class BMW523 {
    	public BMW523(){
    		System.out.println("制造-->BMW523");
    	}
    }
     
    public class Customer {
    	public static void main(String[] args) {
    		BMW320 bmw320 = new BMW320();
    		BMW523 bmw523 = new BMW523();
    	}
    }

            用户需要知道怎么创建一款车,这样子客户和车就紧密耦合在一起了,为了降低耦合,就出现了简单工厂模式,把创建宝马的操作细节都放到了工厂里,而客户直接使用工厂的创建方法,传入想要的宝马车型号就行了,而不必去知道创建的细节。

    1、简单工厂模式的UML图:

    • 工厂类角色: 该模式的核心,用来创建产品,含有一定的商业逻辑和判断逻辑
    • 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。   
    • 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。

    2、代码实现:

    产品类:

    abstract class BMW {
    	public BMW(){}
    }
     
    public class BMW320 extends BMW {
    	public BMW320() {
    		System.out.println("制造-->BMW320");
    	}
    }
    public class BMW523 extends BMW{
    	public BMW523(){
    		System.out.println("制造-->BMW523");
    	}
    }
    

    工厂类:

    public class Factory {
    	public BMW createBMW(int type) {
    		switch (type) {
    		
    		case 320:
    			return new BMW320();
     
    		case 523:
    			return new BMW523();
     
    		default:
    			break;
    		}
    		return null;
    	}
    }

    用户类:

    public class Customer {
    	public static void main(String[] args) {
    		Factory factory = new Factory();
    		BMW bmw320 = factory.createBMW(320);
    		BMW bmw523 = factory.createBMW(523);
    	}
    }

    3、简单工厂模式的优缺点:

            简单工厂模式提供专门的工厂类用于创建对象,实现了对象创建和使用的职责分离,客户端不需知道所创建的具体产品类的类名以及创建过程,只需知道具体产品类所对应的参数即可,通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

            但缺点在于不符合“开闭原则”,每次添加新产品就需要修改工厂类。在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展维护,并且工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。

            为了解决简单工厂模式的问题,出现了工厂方法模式。

    三、工厂方法模式:

            工厂方法模式将工厂抽象化,并定义一个创建对象的接口。每增加新产品,只需增加该产品以及对应的具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。在使用时,用于只需知道产品对应的具体工厂,关注具体的创建过程,甚至不需要知道具体产品类的类名,当我们选择哪个具体工厂时,就已经决定了实际创建的产品是哪个了。

            但缺点在于,每增加一个产品都需要增加一个具体产品类和实现工厂类,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

    1、工厂方法的 UML 结构图如下:

    • 抽象工厂 AbstractFactory: 工厂方法模式的核心,是具体工厂角色必须实现的接口或者必须继承的父类,在 Java 中它由抽象类或者接口来实现。 
    • 具体工厂 Factory:被应用程序调用以创建具体产品的对象,含有和具体业务逻辑有关的代码
    • 抽象产品 AbstractProduct:是具体产品继承的父类或实现的接口,在 Java 中一般有抽象类或者接口来实现。 
    • 具体产品 Product:具体工厂角色所创建的对象就是此角色的实例。

    2、代码实现:

    产品类:

    abstract class BMW {
    	public BMW(){}
    }
    public class BMW320 extends BMW {
    	public BMW320() {
    		System.out.println("制造-->BMW320");
    	}
    }
    public class BMW523 extends BMW{
    	public BMW523(){
    		System.out.println("制造-->BMW523");
    	}
    }
    

    工厂类:

    interface FactoryBMW {
    	BMW createBMW();
    }
     
    public class FactoryBMW320 implements FactoryBMW{
     
    	@Override
    	public BMW320 createBMW() {
    		return new BMW320();
    	}
     
    }
    public class FactoryBMW523 implements FactoryBMW {
    	@Override
    	public BMW523 createBMW() {
    		return new BMW523();
    	}
    }
    

    客户类:

    public class Customer {
    	public static void main(String[] args) {
    		FactoryBMW320 factoryBMW320 = new FactoryBMW320();
    		BMW320 bmw320 = factoryBMW320.createBMW();
     
    		FactoryBMW523 factoryBMW523 = new FactoryBMW523();
    		BMW523 bmw523 = factoryBMW523.createBMW();
    	}
    }
    

    四、抽象工厂模式:

            在工厂方法模式中,我们使用一个工厂创建一个产品,一个具体工厂对应一个具体产品,但有时候我们需要一个工厂能够提供多个产品对象,而不是单一的对象,这个时候我们就需要使用抽象工厂模式。

            在介绍抽象工厂模式前,我们先厘清两个概念:

    • 产品等级结构:产品等级结构指的是产品的继承结构,例如一个空调抽象类,它有海尔空调、格力空调、美的空调等一系列的子类,那么这个空调抽象类和他的子类就构成了一个产品等级结构。
    • 产品族:产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。比如,海尔工厂生产海尔空调、海尔冰箱,那么海尔空调则位于空调产品族中。

    产品等级结构和产品族结构示意图如下:

    1、什么是抽象工厂模式:

            抽象工厂模式主要用于创建相关对象的家族。当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,能够保证客户端始终只使用同一个产品族中的对象;并且通过隔离具体类的生成,使得客户端不需要明确指定具体生成类;所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只需要改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。

            但该模式的缺点在于添加新的行为时比较麻烦,如果需要添加一个新产品族对象时,需要更改接口及其下所有子类,这必然会带来很大的麻烦。

    2、UML结构图:

    • 抽象工厂 AbstractFactory:定义了一个接口,这个接口包含了一组方法用来生产产品,所有的具体工厂都必须实现此接口。
    • 具体工厂 ConcreteFactory:用于生产不同产品族,要创建一个产品,用户只需使用其中一个工厂进行获取,完全不需要实例化任何产品对象。
    • 抽象产品 AbstractProduct:这是一个产品家族,每一个具体工厂都能够生产一整组产品。
    • 具体产品 Product

    3、代码实现:

            通过抽象工厂模式,我们可以实现以下的效果:比如宝马320系列使用空调型号A和发动机型号A,而宝马230系列使用空调型号B和发动机型号B,在为320系列生产相关配件时,就无需制定配件的型号,它会自动根据车型生产对应的配件型号A。

            也就是说,当每个抽象产品都有多于一个的具体子类的时候(空调有型号A和B两种,发动机也有型号A和B两种),工厂角色怎么知道实例化哪一个子类呢?抽象工厂模式提供两个具体工厂角色(宝马320系列工厂和宝马230系列工厂),分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化,每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。

    产品类:

    //发动机以及型号  
    public interface Engine {}  
    
    public class EngineA extends Engine{  
        public EngineA(){  
            System.out.println("制造-->EngineA");  
        }  
    }  
    public class EngineBextends Engine{  
        public EngineB(){  
            System.out.println("制造-->EngineB");  
        }  
    }  
     
    //空调以及型号  
    public interface Aircondition {} 
     
    public class AirconditionA extends Aircondition{  
        public AirconditionA(){  
            System.out.println("制造-->AirconditionA");  
        }  
    }  
    public class AirconditionB extends Aircondition{  
        public AirconditionB(){  
            System.out.println("制造-->AirconditionB");  
        }  
    } 
    

    创建工厂类:

    //创建工厂的接口  
    public interface AbstractFactory {  
        //制造发动机
        public Engine createEngine();
        //制造空调 
        public Aircondition createAircondition(); 
    }  
     
    //为宝马320系列生产配件  
    public class FactoryBMW320 implements AbstractFactory{     
        @Override  
        public Engine createEngine() {    
            return new EngineA();  
        }  
        @Override  
        public Aircondition createAircondition() {  
            return new AirconditionA();  
        }  
    }  
    //宝马523系列
    public class FactoryBMW523 implements AbstractFactory {  
         @Override  
        public Engine createEngine() {    
            return new EngineB();  
        }  
        @Override  
        public Aircondition createAircondition() {  
            return new AirconditionB();  
        }  
    } 
    

    客户:

    public class Customer {  
        public static void main(String[] args){  
            //生产宝马320系列配件
            FactoryBMW320 factoryBMW320 = new FactoryBMW320();  
            factoryBMW320.createEngine();
            factoryBMW320.createAircondition();
              
            //生产宝马523系列配件  
            FactoryBMW523 factoryBMW523 = new FactoryBMW523();  
            factoryBMW523.createEngine();
            factoryBMW523.createAircondition();
        }  
    }
    

    工厂模式小结:

    1、工厂方法模式与抽象工厂模式的区别在于:

    (1)工厂方法只有一个抽象产品类和一个抽象工厂类,但可以派生出多个具体产品类和具体工厂类,每个具体工厂类只能创建一个具体产品类的实例。

    (2)抽象工厂模式拥有多个抽象产品类(产品族)和一个抽象工厂类,每个抽象产品类可以派生出多个具体产品类;抽象工厂类也可以派生出多个具体工厂类,同时每个具体工厂类可以创建多个具体产品类的实例


    设计模式系列文章:

    Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)

    Java设计模式之创建型:建造者模式

    Java设计模式之创建型:单例模式

    Java设计模式之创建型:原型模式

    Java设计模式之结构型:适配器模式

    Java设计模式之结构型:装饰器模式

    Java设计模式之结构型:代理模式

    Java设计模式之结构型:桥接模式

    Java设计模式之结构型:外观模式

    Java设计模式之结构型:组合模式

    Java设计模式之结构型:享元模式

    Java设计模式之行为型:策略模式

    Java设计模式之行为型:模板方法模式

    Java设计模式之行为型:责任链模式

    Java设计模式之行为型:观察者模式

    Java设计模式之行为型:访问者模式

    Java设计模式之行为型:中介者模式

    Java设计模式之行为型:命令模式

    Java设计模式之行为型:状态模式

    Java设计模式之行为型:备忘录模式

    Java设计模式之行为型:迭代器模式

    Java设计模式之行为型:解释器模式


    参考文章:

    设计模式读书笔记----简单工厂模式_chenssy 的技术博客-CSDN博客

    设计模式读书笔记----工厂方法模式_chenssy 的技术博客-CSDN博客

    设计模式读书笔记----抽象工厂模式_chenssy 的技术博客-CSDN博客

    JAVA设计模式之抽象工厂模式_一个本科小生的奋斗史-CSDN博客_java抽象工厂模式

    展开全文
  • 1 简单工厂(Simple Factory) 1.1 问题引出 假如有一个披萨店,Pizza的种类有很多,如CheesePizza、VeggiePizza、PepperPizza等。披萨店根据收到的订单制作Pizza,披萨的制作流程有材料的准备材料、烤、切、包装几步...

    1 简单工厂(Simple Factory)

    1.1 问题引出

    假如有一个披萨店,Pizza的种类有很多,如CheesePizza、VeggiePizza、PepperPizza等。披萨店根据收到的订单制作Pizza,披萨的制作流程有材料的准备材料、烤、切、包装几步。如何设计Pizza的订购呢?按照一般的设计思路:

    那么当用户订购时:

        Pizza OrderPizza(String orderType) {
            Pizza pizza;
    
            if (orderType.equals("veggie")) {
                pizza = new VeggiePizza();
            } else if (orderType.equals("cheese")) {
                pizza = new CheesePizza();
            } else if (orderType.equals("pepper")) {
                pizza = new PepperPizza();
            }
            
            // pizza制作过程
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }
    

    然而当披萨店增加或者删除披萨类型时,必须修改OrderPizza的代码。例如想要添加一个“中国披萨”,那么就要添加:

            else if (orderType.equals("china")) {
                pizza = new ChinaPizza();
            }
    

    也就是说,只要披萨菜单存在改动,这段代码就得一改再改,这种设计明显违反了“开放-关闭原则” ,并没有做到对修改“关闭”。同时,如果有多个订单,那么每个订单也必须依赖每个子类,这样就显得冗杂。如何优化呢?这里得引出“简单工厂模式”了。

    1.2 定义与结构

    简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,简单工厂模式中专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

    直白地讲,简单工厂把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个具体子类来实例化,这样做能把客户类和具体子类的实现解耦,客户类不再需要知道有哪些子类以及应当实例化哪个子类。

    简单工厂模式并不在 GoF 23 种设计模式之列,与其说其是设计模式,不如说是一种编程习惯

    简单工厂模式中包含如下角色:

    • Factory:工厂角色

      工厂角色负责实现创建所有实例的内部逻辑。

    • Product:抽象产品角色

      抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口。

    • ConcreteProduct:具体产品角色

      具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

    类图

    时序图

    1.3 实现

    将简单工厂模式运用到上面的披萨店中,那么就得建造一个SimpleFactory工厂类,它被所有需要进行实例化的客户类调用。

    public class SimpleFactory {
        public Pizza createPizza(String orderType) {
            Pizza pizza = null;
    
            if (orderType.equals("veggie")) {
                pizza = new VeggiePizza();
            } else if (orderType.equals("cheese")) {
                pizza = new CheesePizza();
            } else if (orderType.equals("pepper")) {
                pizza = new PepperPizza();
            }
            return pizza;
        }
    }
    

    客户代码为:

    public PizzaStore{
        SimpleFactory simpleFactory;
        
        public OrderPizza(SimpleFactory simpleFactory) {
            this.simpleFactory = simpleFactory;
        }
        
    	public Pizza orderPizza(String orderType) {
            Pizza pizza;
            
            pizza = simpleFactory.createPizza(orderType);
            
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }
        
        // 其他方法
    }
    

    1.4 小结

    优点

    • 工厂类含有必要的判断逻辑,可决定创建产品类的实例的实际时刻。工厂和产品的职责区分明确,客户端仅仅“消费”产品。
    • 客户端只需要知道具体产品类所对应的参数即可。
    • 通过引入配置文件,可在不修改任何客户端代码的情况下更换和增加新的具体产品类,提高了系统的灵活性。

    缺点

    • 工厂类集中了所有产品创建逻辑,职责过重,一旦发生异常,整个系统将受影响。
    • 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
    • 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂。
    • 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

    适用场景

    对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。

    • 如JDK类库中工具类java.text.DateFormat,它用于格式化一个本地日期或者时间。
    public final static DateFormat getDateInstance();
    public final static DateFormat getDateInstance(int style);
    public final static DateFormat getDateInstance(int style,Locale locale);
    

    2 工厂方法(Factory Method)

    2.1 问题引出

    假如披萨店在各个地儿都有,比如Beijing,Shanghai…他们都保有他们城市的风味。要吃到不同城市风味的披萨,如果运用简单工厂模式:

    // 这里创建的工厂,全是在北京地区的工厂
    BeijingFactory beijingFactory = new BeijingFactory();
    // 创建一个披萨店,将北京工厂的引用作为参数
    PizzaStore pizzaStore = new PizzaStore(beijingFactory);
    // 制作披萨时,就会得到在北京地区的奶酪披萨
    pizzaStore.orderPizza("CheesePizza");
    

    同理,上海的披萨店也类似:

    ShanghaiFactory shanghaiFactory = new ShanghaiFactory();
    PizzaStore pizzaStore = new PizzaStore(shanghaiFactory);
    pizzaStore.orderPizza("CheesePizza");
    

    然而,这样使得代码缺乏弹性。如何弹性地制作出具有一定规范但又不失本地特色的披萨呢?这里就得引出工厂方法模式了。

    2.2 定义与结构

    工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。

    直白地讲,“工厂方法模式”是对简单工厂模式的进一步抽象化,只是工厂方法把产品的实例化操作推迟到子类

    工厂方法模式由4个要素构成。

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

    类图

    时序图

    2.3 实现

    还是以上面披萨制作为例,那么就可以把createPizza(style)放回PizzaStore中,不过设置为“抽象方法”,然后每个区域设置自己的PizzaStore子类。

    public abstract class PizzaStore {
    	public Pizza orderPizza(String orderType) {
            Pizza pizza;
            
            pizza = createPizza(orderType);
            
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }
        
        abstract Pizza createPizza(String orderType);
    }
    

    那么创造怎么样口味的披萨由子类工厂决定:

    public class MyStyleStore extends PizzaStore {
        Pizza createPizza(String type) {
            if (type.equals("veggie")) {
                pizza = new MyStyleVeggiePizza();
            } else if (type.equals("cheese")) {
                pizza = new MyStyleCheesePizza();
            } else if (type.equals("pepper")) {
                pizza = new MyStylePepperPizza();
            }
        }
    }
    
    public class BeijingStore extends PizzaStore {
        Pizza createPizza(String type) {
            if (type.equals("veggie")) {
                pizza = new BeijingVeggiePizza();
            } else if (type.equals("cheese")) {
                pizza = new BeijingCheesePizza();
            } else if (type.equals("pepper")) {
                pizza = new BeijingPepperPizza();
            }
        }
    }
    

    2.4 小结

    优点

    • 用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
    • 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
    • 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。

    缺点

    • 类的个数容易过多,增加复杂度。
    • 考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度。
    • 抽象产品只能生产一种产品。

    适用场景

    在工厂方法模式中,客户端不需知道具体产品类的类名,只需知道创建具体产品的工厂类;对于抽象工厂类,只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象。

    工厂方法模式在JDK类库中运用比较多,例如:

    3 抽象工厂(Abstract Factory)

    3.1 问题引出

    为了更清晰地理解工厂方法模式,先理解两个概念:

    • 产品等级 :产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
    • 产品族 :在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。

    电器工厂的产品等级与产品族

    3.2 定义与结构

    抽象工厂模式(Abstract Factory Pattern):提供一个接口,用于创建创建一系列相关或相互依赖对象的家族,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。

    抽象工厂模式与工厂方法模式区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。

    抽象工厂模式同工厂方法模式一样,也是由4 个要素构成,但抽象工厂中方法个数不同,抽象产品的个数也不同。

    • AbstractFactory:抽象工厂
    • ConcreteFactory:具体工厂
    • AbstractProduct:抽象产品
    • Product:具体产品

    类图

    时序图

    3.3 实现

    public class AbstractProductX {
    }
    
    public class AbstractProductY {
    }
    
    public class ConcreteProductAX extends AbstractProductX {
    }
    
    public class ConcreteProductBX extends AbstractProductX {
    }
    
    public class ConcreteProductAY extends AbstractProductY {
    }
    
    public class ConcreteProductBY extends AbstractProductY {
    }
    
    public abstract class AbstractFactory {
        abstract AbstractProductX createProductX();
        abstract AbstractProductY createProductY();
    }
    
    public class ConcreteFactoryA extends AbstractFactory {
        AbstractProductX createProductX() {
            return new ProductAX();
        }
    
        AbstractProductY createProductY() {
            return new ProductAY();
        }
    }
    
    public class ConcreteFactoryB extends AbstractFactory {
        AbstractProductX createProductX() {
            return new ProductBX();
        }
    
        AbstractProductY createProductY() {
            return new ProductBY();
        }
    }
    
    public class Client {
        public static void main(String[] args) {
            AbstractFactory abstractFactory = new ConcreteFactoryA();
            AbstractProductX productX = abstractFactory.createProductX();
            AbstractProductY productY = abstractFactory.createProductY();
            // do something with productX and productY
        }
    }
    

    3.4 小结

    优点

    • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建,从具体的产品解耦出来。
    • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
    • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。

    缺点

    • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)

    工厂方法模式在JDK类库中的运用:

    4 总结

    严格地讲,简单工厂模式并不在GoF23种设计模式之列,更像是一种编程习惯,也可以理解为工厂方法模式的特殊情况之一。

    • 简单工厂方法实现了客户类与其子类的解耦。

    • 工厂方法模式属于类创建型模式,它把产品的实例化操作也推迟到子类,实现了产品类与其子类的解耦。

    • 抽象工厂模式属于对象创建型模式,相对工厂方法模式针对一个产品等级结构,抽象工厂模式则需要面对多个产品等级结构,一个抽象工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。

    三种设计模式都各有优缺点,在实际开发中,我们应该根据实际业务需求来选择。

    参考

    展开全文
  • 简单工厂模式(女娲造人),工厂(不同厂家生产不同空调),抽象工厂抽象工厂生产一类CPU)
  • Java设计模式 创建型模式 创建者模式概述 创建者模式简介 简单工厂模式 简介 模式结构 练习案例 案例1 案例2 简单工厂模式总结 工厂方法模式 简介 模式结构 练习案例 案例1 工厂方法模式总结 抽象工厂模式 简介 ...
  • 为什么会出现简单工厂,工厂方法简单工厂还有抽象工厂到底有啥区别,什么时候能用到这些呢,如果你对于这些不是很清晰,那么你可以看看小编的这篇博客,透析式挖掘三者的区别!不要错过哟! 这里所有的类图均用...
  • NULL 博文链接:https://1193355343.iteye.com/blog/2370838
  • 包括简单工厂,工厂方法模式,抽象工厂模式三个demo,帮你更好的创建对象
  • 简单工厂:是由一个工厂对象决定创建出哪一种产品类的实例。 A实例调用B实例的方法,称为A依赖于B。如果使用new关键字来创建一个B实例(硬编码耦合),然后调用B实例的方法。一旦系统需要重构:需要使用C类来代替B...
  • NULL 博文链接:https://mrpengpengda.iteye.com/blog/1536290
  • 简单工厂、工厂方法抽象工厂区别

    万次阅读 多人点赞 2018-08-17 11:38:19
    结合简单示例和UML图,讲解工厂模式简单原理。 一、引子 话说十年前,有一个爆发户,他家有三辆汽车(Benz(奔驰)、Bmw(宝马)、Audi(奥迪)),还雇了司机为他开车。不过,爆发户坐车时总是这样:上Benz车后跟...
  • 目前工厂模式大致分为3种,分别是:简单工厂模式、工厂方法模式、抽象工厂模式
  • 一:简单工厂 模型: 案例: namespace 简单工厂 { class Program { static void Main(string[] args) { Factory f = new Factory(); f.N1("大众"); f.N2("保时捷"); ...
  • 这是代码,介绍请查看以下博客地址: http://www.cnblogs.com/homg/p/3548110.html代码乱码请使用utf-8编码。
  • 工厂模式在一些设计模式的书中分为简单工厂模式,工厂方法模式和抽象工厂模式三类。也有把工厂方法模式划分到抽象工厂模式的,认为工厂方法抽象工厂模式的特例的一种,就是只有一个要实现的产品接口。
  • 简单工厂方法、工厂方法以及抽象工厂方法的区别
  • 关于简单工厂模式,工厂方法模式,抽象工厂模式的一次总结 模式 定义 简单工厂模式 定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。 工厂方法模式 定义一个...
  • 本文章通俗易懂的对工厂模式进行了讲解,相信您看完这篇文章会对工厂模式有更深入的了解
  • 熵增教育-熵增学院VIP精品课程录播:简单工厂模式-工厂方法模式-抽象工厂模式
  • 在说设计模式的工厂方法模式之前时,先了解了一下简单工厂。 简单工厂 简单工厂属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象...
  • 工厂方法模式使用Factory模式替代使用new创建对象;抽象工厂模式使用迭代模式创建对象 定义变量不同。简单工厂模式使用参数或者配置文件等事先定义好的变量,然后利用分支判断初始化具体产品类并返回;工厂方法模式...
  • 简单工厂模式又 叫静态工厂方法模式(Static FactoryMethod Pattern),是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。 简单工厂定义一个Factory类,可以根据参数的不同返回不同...
  • NULL 博文链接:https://jacky-dai.iteye.com/blog/2296369

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 142,725
精华内容 57,090
关键字:

简单工厂工厂方法抽象工厂