工厂三兄弟之简明工厂形式(四),工厂形式是最常用的一类创立型设计情势

简易工厂情势

  1. 统筹思想主导流程如下:

      
首先将必要创设的各个差别目的(例如各类不一样的Chart对象)的相关代码封装到不一致的类中,那些类称为具体产品类,而将它们公共的代码举办抽象和领取后封装在一个虚幻产品类中,每3个现实产品类都以聊以自慰产品类的子类;然后提供三个工厂类用于创建各类产品,在工厂类中提供3个创办产品的工厂方法,该措施可以依照所传颂的参数差距成立差其余切切实实产品对象;客户端只需调用工厂类的厂子方法并传播相应的参数即可得到三个出品对象。

       不难工厂形式定义如下:

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

        简单工厂模式的大旨境想在于:当您必要哪些,只须求传入3个不易的参数,就可以拿走你所急需的目的,而无须知道其成立细节。简单工厂情势结构相比简单,其主导是工厂类的设计,其社团如图1所示:

图片 1

 

必要:图表库的陈设

        欲基于Java言语开发一套图表库,该图表库能够为运用系统提供种种分化外观的图样,例如柱状图、饼状图、折线图等。

       
图表库设计人士企盼为运用种类开发人士提供一套灵活易用的图表库,而且可以比较便利地对图表库举行扩充,以便可以在今后追加部分新类型的图纸。

 

【学习难度:★★☆☆☆,使用效能:★★★☆☆】
直接出处:http://woquanke.com/books/gof/
梳理和上学:https://github.com/BruceOuyang/boy-design-pattern
简书日期: 2018/03/05
简书首页:https://www.jianshu.com/p/0fb891a7c5ed

本文目录清单:

工厂表哥兄之简单工厂形式(一)

工厂方式是最常用的一类创设型设计情势,平常大家所说的工厂方式是指工厂方法形式,它也是运用效用最高的工厂格局。本章将要学习的粗略工厂格局是工厂方法形式的“四哥”,它不属于GoF
23种设计形式,但在软件开发中选取也较为频繁,经常将它当做学习其余工厂形式的入门。其余,工厂方法情势还有一个人“大哥”——抽象工厂格局。那二种工厂情势异军突起,难度也逐个加大,在软件开发中它们都拿走了广大的应用,成为面向对象软件中常用的创设对象的工具。

1 图表库的陈设性

萨妮软件商店欲基于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个“巨大的”类,在此类的宏图中存在如下多少个难题:
(1)
在Chart类中涵盖众多“if…else…”代码块,整个类的代码分外冗长,代码越长,阅读难度、维护难度和测试难度也越大;而且多量尺码语句的留存还将影响系统的品质,程序在执行进度中要求做大批量的规格判断。

(2)
Chart类的职分过重,它负责初步化和展现全部的图片对象,将各个图片对象的开始化代码和浮现代码集中在1个类中得以落成,违反了“单一义务规范”,不便民类的录取和保证;而且将大气的靶子初叶化代码都写在构造函数司令员导致构造函数分外巨大,对象在开创时索要开展规范判断,降低了对象创立的功效。

(3)
当需求充实新类型的图形时,必须修改Chart类的源代码,违反了“开闭原则”。

(4)
客户端只好通过new关键字来一贯创立Chart对象,Chart类与客户端类耦合度较高,对象的创立和拔取无法分开。

(5)
客户端在开创Chart对象在此之前大概还索要开展大量开端化设置,例如设置柱状图的水彩、中度等,倘使在Chart类的构造函数中没有提供3个默许设置,那就只好由客户端来形成起来设置,这一个代码在每回创造Chart对象时都会并发,导致代码的重复。

直面二个那样巨大、职务如此重,且与客户端代码耦合度12分高的类,大家应当怎么做?本章将要介绍的回顾工厂情势将在肯定程度上缓解上述难题。

为何要引入工厂类,大家可参见:创立对象与使用对象——谈谈工厂的功能

工厂三兄弟之大概工厂方式(一)

厂子四弟们之大约工厂格局(二)

2 简单工厂情势概述

简单易行工厂格局并不属于GoF
2三个经典设计格局,但常见将它看做读书其余工厂方式的根基,它的筹划思想很简短,其主导流程如下:

首先将须求创建的各个分化对象(例如各样差距的Chart对象)的相干代码封装到区其他类中,那么些类称为具体产品类,而将它们公共的代码进行抽象和领取后封装在八个虚无产品类中,每三个具体产品类都以用空想来欺骗别人产品类的子类;然后提供二个工厂类用于创设种种产品,在工厂类中提供2个开立产品的厂子方法,该方法可以依照所传颂的参数差别创制不相同的具体产品对象;客户端只需调用工厂类的厂子方法并传播相应的参数即可取得1个出品对象。

简单的讲工厂情势定义如下:

粗略工厂情势(Simple Factory
Pattern):定义2个工厂类,它可以依照参数的不一样重返分歧类的实例,被创建的实例常常都独具协同的父类。因为在简易工厂方式中用于创建实例的章程是静态(static)方法,因而简单工厂情势又被号称静态工厂方法(Static
Factory Method)形式,它属于类创建型情势。

简简单单工厂形式的要领在于:当您需求哪些,只需要传入一个不错的参数,就足以得到你所须求的靶子,而无须知道其创制细节。简单工厂形式结构相比较容易,其主干是工厂类的设计,其布局如图1所示:

图片 2

图1 容易工厂形式社团

在简易工厂形式社团图中蕴藏如下几个角色:

  • Factory(工厂剧中人物):工厂剧中人物即工厂类,它是简简单单工厂情势的宗旨,负责兑现创设全部成品实例的内部逻辑;工厂类可以被外界直接调用,创造所需的出品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它的回到类型为架空产品体系Product。

  • Product(抽象产品剧中人物):它是工厂类所创办的具备目标的父类,封装了各类成品对象的国有方法,它的引入将增强系统的油滑,使得在工厂类中只需定义几个通用的厂子方法,因为兼具创立的切实产品对象都以其子类对象。

  • ConcreteProduct(具体产品剧中人物):它是简单工厂格局的开创目的,全体被创制的靶子都担纲那么些角色的某部具体类的实例。每一种具体产品脚色都持续了抽象产品角色,必要贯彻在抽象产品中宣称的充饥画饼方法。

在简要工厂方式中,客户端通过工厂类来创设1个出品类的实例,而无须直接利用new关键字来创设对象,它是工厂格局家族中最简便的一员。

在拔取简易工厂格局时,首先要求对产品类进行重构,无法设计2个完美的产品类,而需按照实际意况设计一个出品层次结构,将持有产品类公共的代码移至抽象产品类,并在空虚产品类中宣示一些空洞方法,以供差别的切实产品类来促成,典型的架空产品类代码如下所示:

abstract class Product {  
    //所有产品类的公共业务方法  
    public void methodSame() {  
        //公共方法的实现  
    }  

    //声明抽象业务方法  
    public abstract void methodDiff();  
}

在切实可行产品类中完成了抽象产品类中宣示的架空业务方法,不相同的切实产品类可以提供不一致的兑现,典型的求实产品类代码如下所示:

class ConcreteProduct extends Product {  
    //实现业务方法  
    public void methodDiff() {  
        //业务方法的实现  
    }  
}

大致工厂方式的主导是工厂类,在尚未工厂类以前,客户端一般会动用new关键字来平素开立产品对象,而在引入工厂类之后,客户端可以经过工厂类来创设产品,在简短工厂格局中,工厂类提供了三个静态工厂方法供客户端使用,依据所传颂的参数不一样足以创制不一致的出品对象,典型的工厂类代码如下所示:

class Factory {  
    //静态工厂方法  
    public static Product getProduct(String arg) {  
        Product abstractProduct = null;  
        if (arg.equalsIgnoreCase("A")) {  
            abstractProduct = new ConcreteProductA();  
            //初始化设置product  
        }  
        else if (arg.equalsIgnoreCase("B")) {  
            abstractProduct = new ConcreteProductB();  
            //初始化设置product  
        }  
        return abstractProduct;  
    }  
}

在客户端代码中,我们因而调用工厂类的厂子方法即可获取产品对象,典型代码如下所示:

class Client {  
    public static void main(String args[]) {  
        Product abstractProduct;   
        abstractProduct = Factory.getProduct("A"); //通过工厂类创建产品对象  
        abstractProduct.methodSame();  
        abstractProduct.methodDiff();  
    }  
}

厂子四汉子之简明工厂情势(二)

厂子三小兄弟之简明工厂格局(三)

3 完整消除方案

为了将Chart类的任务分开,同时将Chart对象的创制和动用分别,Sunny软件集团开发人员决定动用简便工厂方式对图表库进行重构,重构后的结构如图2所示:

图片 3

图2 图表库结构图

在图2中,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();  
    }  
}

编译并运转程序,输出结果如下:

创建柱状图!
初始化设置柱状图!
显示柱状图!

在客户端测试类中,我们应用工厂类的静态工厂方法创设产品对象,假设须求更换产品,只需修改静态工厂方法中的参数即可,例如将柱状图改为饼状图,只需将代码:

chart = ChartFactory.getChart("histogram");

改为

chart = ChartFactory.getChart("pie");

编译并运营程序,输出结果如下:

创建饼状图!
初始化设置饼状图!
显示饼状图!

工厂三哥兄之简明工厂格局(三)

厂子三兄弟之简明工厂方式(四)

4 方案的矫正

Sunny软件集团开发人士发现在创立具体Chart对象时,每更换2个Chart对象都亟需修改客户端代码中静态工厂方法的参数,客户端代码将要重新编译,那对于客户端而言,违反了“开闭原则”,有没有一种办法能够在不改动客户端代码的前提下更换实际产品对象啊?答案是任其自然的,上边将介绍一种常用的兑现方式。

大家得以将静态工厂方法的参数存储在XML或properties格式的布局文件中,如下config.xml所示:

<?xml version="1.0"?>  
<config>  
    <chartType>histogram</chartType>  
</config>

再通过1个工具类XMLUtil来读取配置文件中的字符串参数,XMLUtil类的代码如下所示:

import javax.xml.parsers.*;  
import org.w3c.dom.*;  
import org.xml.sax.SAXException;  
import java.io.*;  

public class XMLUtil {  
    //该方法用于从XML配置文件中提取图表类型,并返回类型名  
    public static String getChartType() {  
        try {  
            //创建文档对象  
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();  
            DocumentBuilder builder = dFactory.newDocumentBuilder();  
            Document doc;                             
            doc = builder.parse(new File("config.xml"));   

            //获取包含图表类型的文本节点  
            NodeList nl = doc.getElementsByTagName("chartType");  
            Node classNode = nl.item(0).getFirstChild();  
            String chartType = classNode.getNodeValue().trim();  
            return chartType;  
        }     
        catch(Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
    }  
}

在引入了布署文件和工具类XMLUtil之后,客户端代码修改如下:

class Client {  
    public static void main(String args[]) {  
        Chart chart; 

        //读取配置文件中的参数  
        String type = XMLUtil.getChartType();

        //创建产品对象
        chart = ChartFactory.getChart(type);   
        chart.display();  
    }  
}

简易发现,在上述客户端代码中不包罗其余与实际图表对象相关的信息,即使急需转移实际图表对象,只需修改配置文件config.xml,无须修改任何源代码,符合“开闭原则”。

思考

在简练工厂格局中追加新的现实产品时是或不是吻合“开闭原则”?倘诺不符合,原有系统需作出什么修改?

5 不难工厂方式的简化

偶然,为了简化简单工厂情势,大家能够将抽象产品类和工厂类合并,将静态工厂方法移至抽象产品类中,如图3所示:

图片 4

图3 简化的简练工厂方式

在图3中,客户端可以由此产品父类的静态工厂方法,根据参数的例外创制不相同体系的出品子类对象,这种做法在JDK等类库和框架中也常见存在。

6 不难工厂格局总计

粗略工厂方式提供了专门的工厂类用于创造对象,将对象的创制和目的的接纳分别开,它当做一种最简易的工厂方式在软件开发中收获了较为普遍的行使。

  1. 关键优点

简易工厂格局的关键优点如下:

(1)
工厂类包含须要的论断逻辑,可以决定在怎么着时候创制哪二个出品类的实例,客户端可避防除直接成立产品对象的职分,而只是“消费”产品,简单工厂方式落成了目的创制和行使的诀别。

(2)
客户端无须知道所创建的切实产品类的类名,只要求通晓具体产品类所对应的参数即可,对于有些繁杂的类名,通过不难工厂格局可以在一定水平收缩使用者的回忆量。

(3)
通过引入配置文件,能够在不改动任何客户端代码的地方下更换和伸张新的具体产品类,在任天由命程度上提升了系统的油滑。

  1. 主要弱点

简不难单工厂格局的关键弱点如下:

(1)
由于工厂类集中了独具成品的创立逻辑,职分过重,一旦无法平常办事,整个连串都要面临震慑。

(2)
使用简单工厂形式势必会增添系统中类的个数(引入了新的厂子类),伸张了系统的复杂度和精晓难度。

(3)
系统扩充困难,一旦添加新产品就不得不修改工厂逻辑,在产品种类较多时,有只怕引致工厂逻辑过于复杂,不便民系统的扩大和保安。

(4)
简单工厂方式由于选拔了静态工厂方法,造成工厂剧中人物无法形成基于继承的等级结构。

  1. 适用场景

在偏下景况下可以设想动用简便工厂形式:

(1)
工厂类负责创设的对象相比少,由于创立的目的较少,不会导致工厂方法中的业务逻辑太过复杂。

(2) 客户端只驾驭传入工厂类的参数,对于怎么创造对象并不关切。

练习

行使简单工厂形式设计三个方可创制差距几何样子(如圆形、方形和三角形等)的绘图工具,逐个几何图形都兼备绘制draw()和擦除erase()八个办法,须要在绘制不帮衬的几何图形时,指示三个UnSupportedShapeException。

演习会在我的github上做掉

厂子三小兄弟之简单工厂格局(四)

不难工厂格局总计

工厂三小兄弟之简明工厂形式(一)

  工厂情势是最常用的一类成立型设计方式,平常大家所说的工厂方式是指工厂方法格局,它也是利用效能最高的工厂格局。本章将要学习的粗略工厂方式是工
厂方法格局的“四哥”,它不属于 GoF 23
种设计形式,但在软件开发中行使也较为频仍,平常将它作为学习其他工厂方式的入门。其它,工厂方法方式还有壹位“堂弟”——抽象工厂方式。那三种工厂方式各具特色,难度也每种加大,在软件开发中它们都拿到了广大的采纳,成为面向对象软件中常用的创制对象的工具。

图表库的设计

  Sunny 软件公司欲基于 Java
语言开发一套图表库,该图表库可以为利用连串提供各个不相同外观的图形,例如柱状图、饼状图、折线图等。Sunny软件公司图表库设计人士希望为利用系统开发人士提供一套灵活易用的图表库,而且能够相比便宜地对图表库举行扩张,以便可以在今后扩大一些新品类的图片。

萨妮软件商店图表库设计人士提出了一个初阶设计方案,将兼具图表的完结代码封装在三个Chart 类中,其框架代码如下所示:

 1 class Chart {
 2     private String type; //图表类型
 3 
 4     public Chart(Object[][] data, String type) {
 5         this.type = type;
 6         if (type.equalsIgnoreCase("histogram")) {
 7             //初始化柱状图
 8         }
 9         else if (type.equalsIgnoreCase("pie")) {
10             //初始化饼状图
11         }
12         else if (type.equalsIgnoreCase("line")) {
13             //初始化折线图
14         }
15     }
16 
17     public void display() {
18         if (this.type.equalsIgnoreCase("histogram")) {
19             //显示柱状图
20         }
21         else if (this.type.equalsIgnoreCase("pie")) {
22             //显示饼状图
23         }
24         else if (this.type.equalsIgnoreCase("line")) {
25             //显示折线图
26         }   
27     }
28 }

客户端代码通过调用 Chart 类的构造函数来成立图表对象,依据参数 type
的差距足以博得差距类型的图形,然后再调用 display()
方法来呈现相应的图片。

简单看出,Chart 类是二个“巨大的”类,在此类的规划中留存如下多少个难题:

(1) 在 Chart 类中隐含众多 if…else…
代码块,整个类的代码卓绝冗长,代码越长,阅读难度、维护难度和测试难度也越大;而且大批量标准化语句的留存还将震慑系统的属性,程序在实施进度中要求做大批量的原则判断。

(2) Chart
类的任务过重,它承受开首化和突显全体的图纸对象,将各类图片对象的开首化代码和出示代码集中在贰个类中已毕,违反了“单一义务规范”,不便民类的录取和
维护;而且将大气的靶子开端化代码都写在构造函数少校导致构造函数极度庞大,对象在开立刻索要展开标准化判断,下落了对象创制的功用。

(3) 当须求充实新类型的图形时,必须修改 Chart
类的源代码,违反了“开闭原则”。

(4) 客户端只好通过 new 关键字来一贯开立 Chart 对象,Chart
类与客户端类耦合度较高,对象的成立和选用无法分开。

(5) 客户端在创制 Chart
对象此前大概还亟需展开多量开首化设置,例如设置柱状图的颜料、高度等,倘诺在
Chart
类的构造函数中一直不提供三个暗中认同设置,那就不得不由客户端来已毕发轫设置,那几个代码在每趟创制Chart 对象时都会现出,导致代码的重新。

面对三个如此巨大、职分如此重,且与客户端代码耦合度极度高的类,大家应该如何是好?本章将要介绍的简要工厂形式将在肯定程度上解决上述难题。

 

厂子小弟们之大概工厂形式(二)

大约工厂形式并不属于 GoF 2一个经典设计情势,但一般将它作为学习其余工厂情势的根底,它的统筹思想很简短,其主导流程如下:

率先将索要成立的各个差异目标(例如种种差别的 Chart
对象)的有关代码封装到差距的类中,那一个类称为具体产品类,而将它们公共的代码进行抽象和提取后封装在一个抽象产品类中,每2个具体产品类都以空虚产品类
的子类;然后提供三个工厂类用于创建各类成品,在工厂类中提供二个创造产品的工厂方法,该办法可以根据所盛传的参数差别创造区其余求实产品对象;客户端只
需调用工厂类的工厂方法并传到相应的参数即可得到2个产品对象。

简言之工厂格局定义如下:

大约工厂情势(Simple Factory
Pattern):定义1个工厂类,它可以依照参数的不比重临差异类的实例,被创立的实例日常都负有协同的父类。因为在简约工厂情势中用于创立实例的方法
是静态(static)方法,因而简单工厂格局又被号称静态工厂方法(Static
Factory Method)形式,它属于类创立型方式。

简言之工厂形式的中央思想在于:当你须要什么,只必要传入三个毋庸置疑的参数,就能够赢得你所急需的对象,而无须知道其创建细节。简单工厂格局组织比较简单,其宗旨是工厂类的统筹,其结构如图所示:

图片 5

在简练工厂情势结构图中蕴涵如下多少个角色:

  • Factory(工厂角色):工厂角色即工厂类,它是简简单单工厂形式的主干,负责兑现创制全部产品实例的中间逻辑;工厂类可以被外界间接调用,成立所
    需的制品对象;在工厂类中提供了静态的工厂方法
    factoryMethod(),它的回到类型为架空产品品类 Product。

  • Product(抽象产品脚色):它是工厂类所创设的保有目的的父类,封装了各种成品对象的公有方法,它的引入将增加系统的八面见光,使得在工厂类中只需定义三个通用的工厂方法,因为拥有创立的具体产品对象都以其子类对象。

  • ConcreteProduct(具体产品角色):它是粗略工厂方式的创始目的,全部被创造的对象都担纲这些角色的有个别具体类的实例。每叁个切实可行产品脚色都继承了抽象产品角色,须要贯彻在空虚产品中申明的抽象方法。

在简易工厂方式中,客户端通过工厂类来创设三个成品类的实例,而无须直接运用
new 关键字来创造对象,它是工厂情势家族中最简便的一员。

在使用简便工厂形式时,首先需求对产品类举办重构,不可能设计四个圆满的产品类,而需依照实际景况统筹多少个成品层次结构,将富有产品类公共的代码移至抽象产品类,并在空虚产品类中声贝因美些虚无方法,以供区其他现实性产品类来兑现,典型的肤浅产品类代码如下所示:

1 abstract class Product {
2     //所有产品类的公共业务方法
3     public void methodSame() {
4         //公共方法的实现
5     }
6 
7     //声明抽象业务方法
8     public abstract void methodDiff();
9 }

在切实产品类中完成了画饼充饥产品类中宣示的架空业务方法,差其余有血有肉产品类可以提供差其他贯彻,典型的切切实实产品类代码如下所示:

1 class ConcreteProduct extends Product {
2     //实现业务方法
3     public void methodDiff() {
4         //业务方法的实现
5     }
6 }

简易工厂情势的骨干是工厂类,在并未工厂类之前,客户端一般会选择 new
关键字来一直开立产品对象,而在引入工厂类之后,客户端可以透过工厂类来创立产品,在简易工厂形式中,工厂类提供了四个静态工厂方法供客户端使用,按照所
传入的参数差别足以创造分歧的成品对象,典型的厂子类代码如下所示:

 1 class Factory {
 2     //静态工厂方法
 3     public static Product getProduct(String arg) {
 4         Product product = null;
 5         if (arg.equalsIgnoreCase("A")) {
 6             product = new ConcreteProductA();
 7             //初始化设置product
 8         }
 9         else if (arg.equalsIgnoreCase("B")) {
10             product = new ConcreteProductB();
11             //初始化设置product
12         }
13         return product;
14     }
15 }

在客户端代码中,大家通过调用工厂类的工厂方法即可得到产品对象,典型代码如下所示:

1 class Client {
2     public static void main(String args[]) {
3         Product product; 
4         product = Factory.getProduct("A"); //通过工厂类创建产品对象
5         product.methodSame();
6         product.methodDiff();
7     }
8 }

 

工厂三兄弟之不难工厂情势(三)

总体化解方案

为了将 Chart 类的职责分开,同时将 Chart 对象的创造和使用分别,Sunny软件公司开发人士决定动用简便工厂方式对图表库举行重构,重构后的社团如图所示:

 图片 6

在图中,Chart 接口充当抽象产品类,其子类HistogramChart、PieChart 和
LineChart 充当具体产品类,ChartFactory 充当工厂类。完整代码如下所示:

 1 //抽象图表接口:抽象产品类
 2 interface Chart {
 3     public void display();
 4 }
 5 
 6 //柱状图类:具体产品类
 7 class HistogramChart implements Chart {
 8     public HistogramChart() {
 9         System.out.println("创建柱状图!");
10     }
11 
12     public void display() {
13         System.out.println("显示柱状图!");
14     }
15 }
16 
17 //饼状图类:具体产品类
18 class PieChart implements Chart {
19     public PieChart() {
20         System.out.println("创建饼状图!");
21     }
22 
23     public void display() {
24         System.out.println("显示饼状图!");
25     }
26 }
27 
28 //折线图类:具体产品类
29 class LineChart implements Chart {
30     public LineChart() {
31         System.out.println("创建折线图!");
32     }
33 
34     public void display() {
35         System.out.println("显示折线图!");
36     }
37 }
38 
39 //图表工厂类:工厂类
40 class ChartFactory {
41     //静态工厂方法
42     public static Chart getChart(String type) {
43         Chart chart = null;
44         if (type.equalsIgnoreCase("histogram")) {
45             chart = new HistogramChart();
46             System.out.println("初始化设置柱状图!");
47         }
48         else if (type.equalsIgnoreCase("pie")) {
49             chart = new PieChart();
50             System.out.println("初始化设置饼状图!");
51         }
52         else if (type.equalsIgnoreCase("line")) {
53             chart = new LineChart();
54             System.out.println("初始化设置折线图!");            
55         }
56         return chart;
57     }
58 }

编制如下客户端测试代码:

1 class Client {
2     public static void main(String args[]) {
3         Chart chart;
4         chart = ChartFactory.getChart("histogram"); //通过静态工厂方法创建产品
5         chart.display();
6     }
7 }

编译并运行程序,输出结果如下:

创建柱状图!
初始化设置柱状图!
显示柱状图!

在客户端测试类中,大家运用工厂类的静态工厂方法创设产品对象,如果急需转移产品,只需修改静态工厂方法中的参数即可,例如将柱状图改为饼状图,只需将代码:

chart = ChartFactory.getChart("histogram");

改为:

chart = ChartFactory.getChart("pie");

编译并运行程序,输出结果如下:

创建饼状图!
初始化设置饼状图!
显示饼状图!

厂子三兄弟之简明工厂方式(四)

方案的修正

Sunny 软件公司开发人士发未来开立具体 Chart 对象时,每更换三个 Chart
对象都亟需修改客户端代码中静态工厂方法的参数,客户端代码将要重新编译,那对于客户端而言,违反了“开闭原则”,有没有一种办法可以在不改动客户端代码
的前提下更换实际产品对象啊?答案是必定的,下边将介绍一种常用的兑现方式。

大家得以将静态工厂方法的参数存储在 XML 或 properties
格式的布局文件中,如下 config.xml 所示:

 

1 <?xml version="1.0"?>
2 <config>
3     <chartType>histogram</chartType>
4 </config>

再通过1个工具类 XMLUtil 来读取配置文件中的字符串参数,XMLUtil
类的代码如下所示:

 1 import javax.xml.parsers.*;
 2 import org.w3c.dom.*;
 3 import org.xml.sax.SAXException;
 4 import java.io.*;
 5 
 6 public class XMLUtil {
 7     //该方法用于从XML配置文件中提取图表类型,并返回类型名
 8     public static String getChartType() {
 9         try {
10             //创建文档对象
11             DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
12             DocumentBuilder builder = dFactory.newDocumentBuilder();
13             Document doc;                           
14             doc = builder.parse(new File("config.xml")); 
15 
16             //获取包含图表类型的文本节点
17             NodeList nl = doc.getElementsByTagName("chartType");
18             Node classNode = nl.item(0).getFirstChild();
19             String chartType = classNode.getNodeValue().trim();
20             return chartType;
21         }   
22         catch(Exception e) {
23             e.printStackTrace();
24             return null;
25         }
26     }
27 }

在引入了布署文件和工具类 XMLUtil 之后,客户端代码修改如下:

1 class Client {
2     public static void main(String args[]) {
3         Chart chart;
4         String type = XMLUtil.getChartType(); //读取配置文件中的参数
5         chart = ChartFactory.getChart(type); //创建产品对象
6         chart.display();
7     }
8 }

简易发现,在上述客户端代码中不包涵其余与现实图表对象相关的音信,借使须求更换实际图表对象,只需修改配置文件
config.xml,无须修改任何源代码,符合“开闭原则”。

思考

在大约工厂形式中加进新的有血有肉产品时是或不是符合“开闭原则”?就算不吻合,原有系统需作出什么修改?

简不难单工厂形式的简化

有时,为了简化简单工厂格局,大家得以将抽象产品类和工厂类合并,将静态工厂方法移至抽象产品类中,如图所示:

图片 7

在图中,客户端可以经过产品父类的静态工厂方法,依照参数的例外创造不一样类型的产品子类对象,那种做法在
JDK 等类库和框架中也普遍存在。

回顾工厂情势总计

简单易行工厂情势提供了特别的工厂类用于创制对象,将目标的创制和目的的行使分别开,它看作一种最不难易行的厂子方式在软件开发中得到了相比广泛的使用。

重大优点

简单易行工厂情势的紧要优点如下:

(1)
工厂类包罗必要的论断逻辑,可以操纵在怎么着时候创造哪1个产品类的实例,客户端可以解除直接开立产品对象的职责,而单独“消费”产品,不难工厂方式完毕了对象创设和使用的分手。

(2)
客户端无须知道所创办的具体产品类的类名,只须要了然具体产品类所对应的参数即可,对于部分错综复杂的类名,通过简单工厂形式可以在肯定程度减弱使用者的记念量。

(3)
通过引入配置文件,可以在不修改任何客户端代码的处境下转移和充实新的现实性产品类,在早晚水准上加强了系统的灵活性。

重视症结

简短工厂格局的紧要症结如下:

(1)
由于工厂类集中了颇具产品的创导逻辑,职分过重,一旦不大概健康工作,整个系统都要面临震慑。

(2)
使用简便工厂形式势必会伸张系统中类的个数(引入了新的厂子类),增添了系统的复杂度和驾驭难度。

(3)
系统伸张困难,一旦添加新产品就只好修改工厂逻辑,在成品类型较多时,有大概导致工厂逻辑过于复杂,不便宜系统的扩张和掩护。

(4)
简单工厂格局由于应用了静态工厂方法,造成工厂角色不能够形成基于继承的级差结构。

适用场景

在偏下意况下可以设想使用简易工厂方式:

(1)
工厂类负责成立的目的相比少,由于成立的靶子较少,不会促成工厂方法中的业务逻辑太过复杂。

(2) 客户端只略知一二传入工厂类的参数,对于哪些创设对象并不爱惜。

练习

采用简单工厂方式设计三个可以创制分裂几何样子(如圆形、方形和三角形等)的绘图工具,逐个几何图形都存有绘制
draw() 和擦除 erase() 五个办法,须求在绘制不支持的几何图形时,指示1个UnSupportedShapeException。

 

 

 

 

 

 

 

 

 

相关文章