• 设计模式:工厂三姐妹一网打尽


    作为创建型设计模式,带有工厂名字的设计模式共有三个,分别是

    1. Simple Factory
    2. Factory Method
    3. Abstract Factory

    其中的 Simple Factory并不是GoF一书中的模式,但是它是最基础最常用的,并且也是循序渐进的了解另外两个工厂的必要基础,所有放在一起讲它们是比较科学的。

    三者常常是容易搞混的,我就见过若干个搞混的案例。要么,比起这更难的,是不太容易弄明白使用的场景和目的。本文试图通过一个案例,讲清楚三者的内涵,但是不准备讲解它的外延。

    假设我们想要做一个图形编辑器,我们把它的需求压低到极为简洁的形式,只要和当前要描述的问题无关的,我们都不会引入:

    1. 可以创建两种形状,矩形和圆形
    2. 可以设置形状的颜色,红色和黄色

    那么,系统中必然需要如下的Shape类:

    class Shape{draw(){}}
    class Rect extends Shape{draw(){}}
    class Circle extends Shape{draw(){}}

    以及,系统中必然需要如下的Color类:

    class Color{fill(){}}
    class Red extends Color{fill(){}}
    class Yellow extends Color{fill(){}}

    我们首先从Shape开始。假设需要创建一个矩形,我们可以这样做:

    var rect = new Rect()

    需要一个圆形也简单:

    var rect = new Circle()
    

    实际上,我们通常是在界面上,一般是工具栏上,放置两个按钮,让用户选择哪个按钮,然后创建此形状。用户选择了矩形,接下来创建就是矩形,选择的是圆形,那么创建就是圆形。所以这样的代码一定是存在的:

    if (userSelected = "rect")
      return new Rect()
    if (userSelected = "circle")
      return new Circle()

    Simple Factory

    Simple Factory的价值就是让调用者从创建逻辑中解脱,只要传递一个参数,就可以获得创建对象。实际上,从对象职责来说,这段代码不应该是Rect或者是Circle的,也不应该是UI类的,UI类在不同的应用中是不一样的,但是我们知道作为顶层类,需要负责UI显示和事件,不应该负责创建对象的逻辑。实际上,很多代码放到此处,特别容易导致代码拥挤,主控类职责过多的问题。

    最好引入一个新的类,像是这样:

    class ShapeCREATEOR{
        create(userSelected){
            if (userSelected = "rect")
              return new Rect()
            if (userSelected = "circle")
              return new Circle()
        }
    }

    这个类的所有逻辑,都是专门用于创建其他类。因为非常常见,人们为他取名为Factory,其他被创建的类被称为Product。所以惯例上来说,此类的名字会冠以工厂名:

    class ShapeFactory

    根据传入的参数,决定创建哪一个产品类,此类就被称为简单工厂类(Simple Factory)。有了工厂类,使用者就可以直接使用工厂类获得需要的对象:

    var sf = new ShapeFactory()
    var rect = sf.create("rect")
    

    于是,所有需要创建矩形的场合,你知道,一个UI App,除了工具栏,还有菜单,都只要写这样的代码就可以创建了。而不必到处根据userSelected来做分支了。这就是使用工厂的好处。如果支持命令创建,甚至使用json文件中恢复对象时,本来也需要传递字符串来决定创建对象时,就显得简单工厂的好处了。

    factory method

    简单工厂根据传入的参数决定实例化哪一个类,而factory method有子类来决定实例化哪一个类。

    class Shape{draw(){}}
    class Rect extends Shape{draw(){}}
    class Circle extends Shape{draw(){}}
    class ShapeFactory{
        createShape(){}
    }
    class RectFactory extends ShapeFactory{
        createShape(){return new Rect()}
    }
    class CircleFactory extends ShapeFactory{
        createShape(){return new Circle()}
    }
    

    调用者需要创建Rect,只要这样:

      var f = new RectFactory()
      f.createShape()
    

    这是factory method的定义:

     创建一个接口,但是由子类决定实例化哪一个类
     

    这里提到的接口是ShapeFactory.createShape,提到的子类为:RectFactory,CircleFactory。这样做就意味着,在工厂内不必根据传入参数分支,它作为子类本身就知道要创建的是哪一个产品。使用对应的工厂,创建需要的类。

    AbstractFactory

    要是我们创建的类型不仅仅是Shape,还有Color的话,AbstractFactory就有价值。AbstractFactory提供一个接口a,此接口可以创建一系列相关或者相互依赖的对象b,使用用户不需要指定具体的类即可创建它们c。

    我们先看代码:

    class Shape{draw(){}}
    class Rect extends Shape{draw(){}}
    class Circle extends Shape{draw(){}}
    class ShapeFactory{
        createShape(type){
            if (shape == "rect"){
                return new Rect()
            }else{
                return new Circle()
            }
        }
    }
    class Color{fill(){}}
    class Red extends Color{fill(){}}
    class Yellow extends Color{fill(){}}
    class ColorFactory {
        creatColor(type){
            if (shape == "Red"){
                return new Red()
            }else if (shape == "Yellow"{
                return new Yellow()
            }
        }
    }
    

    如果希望客户可以一个单一接口来访问Color和Shape,可以引入一个抽象工厂:

    class AbstractFactory{
        createShape(){}
        createColor(){}
    }
    

    要求两个工厂实现此抽象工厂:

    class ShapeFactory extends AbstractFactory{
        createShape(type){
            if (shape == "rect"){
                return new Rect()
            }else{
                return new Circle()
            }
        }
        createColor(){
            return null
        }
    }
    
    class ColorFactory extends AbstractFactory{
        createShape(type){return null}
        creatColor(type){
            if (shape == "Red"){
                return new Red()
            }else if (shape == "Yellow"{
                return new Yellow()
            }
        }
    }

    自己不具备的能力,不实现即可,这里就是返回一个null。需要一个创建工程的简单工厂

    class FactoryProducer{
        getFactory(type){
            if (type == "color")return new ColorFactory()
                else return new ShapeFactory()
        }
    }
    

    没有抽象工厂,那么代码是这样的,所有的Factory类的创建都是硬编码的

    var sf = new ShapeFactory()
    var r = sf.createColor("Rect")
    r.draw()
    var cf = new ColorFactory()
    var c = cf.createColor("Red")
    c.fill()
    

    有了抽象工厂,那么客户的使用就是这样

    var fp = new FactoryProducer()
    var sf = fp.getFactory("shape")
    var r = sf.createColor("Rect")
    r.draw()
    var cf = fp.getFactory("color")
    var c = cf.createColor("Red")
    c.fill()
    

    好处是,硬编码创建的类只有一个,就是FactoryProducer。

    其中难懂的部分,做一个进一步说明:

    1. 接口a:AbstractFactory内的两个函数createShape,createColor
    2. 一系列相关或者相互依赖的对象b: Shape系列类,Color系列类
    3. 使用用户不需要指定具体的类即可创建它们c:实际上,用户只要使用FactoryProducer这一个类,不需要使用任何一个工厂,以及工厂创建的类。

    本文host于 https://github.com/1000copy/d... ,欢迎folk。

  • 相关阅读:
    解决 DBMS_AW_EXP: BIN$*****==$0 not AW$
    物化视图(materialized view) 实现数据迁移、数据定时同步
    Mysql exists 与 in
    ORACLE DATAGUARD 进程
    ORACLE DATAGUARD SWITCHOVER 步骤
    Oracle Dataguard failover 操作步骤
    Python 包管理(PYPA)
    Emacs Org-mode 4 超连接
    Emacs Org-mode 3 表格
    ycmd for emacs 代码自动补全
  • 原文地址:https://www.cnblogs.com/twodog/p/12137952.html
Copyright © 2020-2023  润新知