工厂模式与OO设计原则

        发现变化隔离封装变化是动因,关闭修改打开扩展是限制;简单工厂很好地遵照了DRY原则,对OCP原则支持不足;工厂方法模式彻底支持了OCP原则,使用的机制是继承;工厂方法模式都彻底支持OCP原则;LSP原则是OCP成为可能的重要原则,抽象工厂模式、工厂方法模式彻底遵照LSP 。
      若是把建立看做一个职责,那么系统中的哪一个对象应该拥有这个职责呢?若是把建立看做知识,那么建立知识应该放置在什么地方呢?说到职责咱们不得不说一下著名的GRASP原则:
GRASP是通用职责分配软件模式(General Responsibility Assignment Software patterns)的简称。它包含了9大模式,分别以下所示:
        1  建立者(Creator) :决定对象应该有谁来建立的问题。
        2  信息专家(Information expert):用此模式来肯定如何给对象分配职责的问题。通常把职责分配给那些包含此职责有关信息的对象。这样也体现了高内聚性模式。
        3 低耦合(Low coupling)
        4 控制器(Controller).
        5 高内聚(High Cohesion)
        6 多态性(polymorphism)
        7 纯虚构(pure fabrication)
        8 间接性(indirection)
        9 防止变异 (protected variations)
     
能够看出GRASP很是关注对象由谁来建立,并给出了一个职责分配的解决模型:信息专家模式;咱们没必要深究GRASP的种种细节,咱们从上面的表述中能够获得这样的启示:
  • 对象的建立不是随意性的,也是有规范能够遵循的,咱们能够从中获得灵活性和可维护性;
  • 职责分配给这个职责相关的信息专家,即:最适合的人作最适合的事情
 
       当建立一个对象的知识散布在系统的各处的时候,这种蔓延现象实际上说明了系统建立职责分配的混乱,缺乏一个进行拥有建立知识的信息专家(请注意这里的表述)。 建立逻辑一般是这样的,它包含了一系列if-else的判断逻辑,根据运行时的具体参数来决定对象的建立。若是这部分是肯定的那么咱们也没必要过多的考虑它。可是若是它是变化的,好比删减一个对象的建立或者增长一个新类型的建立,那么这部分代码是要被常常修改的,这种修改实际上说明咱们已经违反了OCP原则(关闭修改,打开扩展),那么根据识别变化封装变化的原则 咱们必须把这一部分进行抽取并进行隔离。
      翻看全部设计模式相关的书籍咱们均可以看到这样的表述:
      工厂模式专门负责将大量有共同接口的类实例化。工厂模式能够在运行时动态决定将哪个类实例化。
    
    
看样子工厂模式正是咱们须要的,但咱们并不急于下手,看看是否是另有蹊径,[接口]怎么样?《Java与模式》一书就是给出了这样一个接口实现的方式。
       我习惯把接口理解成契约和行为,建立出来不一样的对象,对象的区别实际上行为的差异。接口是否是能够?假设我么使用了接口,问题解决了么?没有!增长新类时一样面临修改代码的问题。这个方法只是转化了问题的形式,并无真正解决问题,使用接口咱们失去的代码复用的优点,而大量的具体类上使用接口不是什么好主意,虽然《Java 与模式》一书所有使用接口实现。若是要建立的对象没有共同的业务逻辑那么可使用一个接口来扮演抽象产品的角色,可是更多的状况是具体产品之间是存在共有的业务逻辑,那么这些逻辑就应该移到抽象角色里面。
      其实咱们就是将建立知识集中并设立一个信息专家专门负责对象的建立。简单工厂模式是咱们的第一个拥有建立知识的信息专家:
简单工厂
      咱们考虑最简单的抽取和隔离方法就是使用[ 简单工厂]。简单工厂的特色就是参数化建立对象,简单工厂必须知道每一种产品以及什么时候提供给Client。有人会说简单工厂仍是换汤不换药,添加新类的时候仍是须要修改这部分的代码!诚然,那么咱们得到了什么好处呢?集中变化! 这很好的符合了DRY原则(Don't Repeat Yourself!)建立逻辑存放在单一的位置,即便它变化,咱们也只须要修改一处就能够了。DRY 很简单,但倒是确保咱们代码容易维护和复用的关键。DRY原则同时还提醒咱们:对系统职能进行良好的分割!职责清晰的界限必定程度上保证了代码的单一性。 这句话对咱们后续的分析极具指导意义,毕竟简单工厂只是低层次上的代码复用。
    
      题外话:简单工厂的确简单可是其背后的DRY原则在实践中让咱们受益不浅,去年我和个人搭档作站点的升级工做,写了不少重复的代码;代码重复,源代码组织混乱,没有作好规划和职责分析是原罪。今年新项目,DRY 原则是我头顶的达摩克利斯之剑,不作重复的事情成为我进行项目计划组织管理的重要标准。
    关于简单工厂模式的阶段总结:
  • 识别变化隔离变化,简单工厂是一个显而易见的实现方式
  • 简单工厂将建立知识集中在单一位置符合了DRY
  • 客户端无须了解对象的建立过程,某种程度上支持了OCP
  • 添加新的产品会形成建立代码的修改,这说明简单工厂模式对OCP支持不够
  • 简单工厂类集中了全部的实例建立逻辑很容易违反高内聚的责任分配原则。
     
Factory Method模式
    简单工厂模式之因此对OCP支持不够,就是由于它拥有了太多的知识:有多少种产品以及建立产品的时机。或者说,简单工厂承担了太多的职责。DRY 原则提示咱们要清晰的划清对象职责的界限。一个方法就是权力下放,将建立的知识移交给子类。知识的递交意味着职责的转移。
   
这样作以后,咱们从新审视类之间的关系:核心工厂类再也不负责全部产品的建立,核心类的层次上升成为一个抽象工厂角色,仅仅负责给出具体子类必须实现的接口,而不关系具体产品的建立细节。建立的知识由具体工厂拥有。而这时系统内也出现了一个平行的等级结构,产品家族的等级结构以及对应的工厂等级结构。
    简单工厂把核心放在一个具体类上。Factory Method模式把核心放在抽象类,具体工厂类继承了建立行为。具体工厂都拥有相同的接口因此还有一个别名叫多态工厂模式。这是咱们关注点已经从实现转移到了“接口”:关注动机而非实现,是基本的OO设计原则,将实现隐藏在接口以后其实是将对象的实现与它们的对象解耦了。从“依赖”的角度,系统中依赖的已经再也不是一个个具体的实现,而是一个抽象。这就是DIP原则高层模块不该该依赖低层模块,二者都应该依赖于抽象。这个原则隐含的意思是:对象之间只在概念层次存在耦合,在实现层次不能耦合!
     工厂方法模式的应用须要彻底遵照里氏替换原则 为前提。即父类出现的地方可以替换成子类,工厂方法模式的应用才能成为可能。
      咱们要添加一个新的产品,只要添加这个产品类和它的工厂类就能够了。没有必要修改Client和已经存在的工厂代码。Factory Method彻底支持OCP原则


 抽象工厂模式

    抽象工厂向客户端提供了一个接口,使得客户端在不指定具体产品类型的时候就能够建立产品族中的产品对象。这就是抽象工厂的用意。抽象工厂面的问题是多个等级产品等级结构的系统设计。抽象工厂和工厂方法模式最大的区别就在于后者只是针对一个产品等级结构;而抽象工厂则是面对多个等级结构。
      一样出色的完成了把应用程序从特定的实现中解耦,工厂方法使用的方法是继承,而抽象工厂使用的对象组合。抽象工厂提供的是一个产品家族的抽象类型,这个类型的子类完成了产品的建立。
       咱们在工厂方法模式中提到的OCP DIP LSP等原则的表述也适用于抽象工厂模式.

       我曾经在《视角的力量--再说OO 设计原则》一文中提到抽象出来高层策略是须要有必定稳定性的。抽象工厂做为一个高层抽象若是它的接口发生变化,那么影响是巨大的:全部的子类都要进行修改!这就要求抽象工厂的接口设计是高度抽象的!
 
总结:
  • 发现变化隔离封装变化是动因,关闭修改打开扩展是限制
  • 简单工厂很好地遵照了DRY原则,对OCP原则支持不足
  • 工厂方法模式彻底支持了OCP原则,使用的机制是继承
  • 抽象工厂模式 工厂方法模式都彻底支持OCP原则
  • LSP原则是OCP成为可能的重要原则,抽象工厂模式、工厂方法模式彻底遵照LSP
  • 依赖于抽象,一个类派生自具体类明显违背了DIP原则
  • GRASP是另一个设计模式体系,它与GOF设计模式在不少地方是异曲同工,了解一下GRASP能够帮助咱们思考 
相关文章
相关标签/搜索