zoukankan      html  css  js  c++  java
  • 设计模式:工厂三姐妹一网打尽

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

    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。

  • 相关阅读:
    leetcode 18 4Sum
    leetcode 71 Simplify Path
    leetcode 10 Regular Expression Matching
    leetcode 30 Substring with Concatenation of All Words
    leetcode 355 Design Twitte
    leetcode LRU Cache
    leetcode 3Sum
    leetcode Letter Combinations of a Phone Number
    leetcode Remove Nth Node From End of List
    leetcode Valid Parentheses
  • 原文地址:https://www.cnblogs.com/twodog/p/12137950.html
Copyright © 2011-2022 走看看