6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式

注:《大话设计模式》这本书很好的介绍了设计模式,其对应的源码是C#语言写得,跑在visual studio上,所以自己先安装visual studio ,然后将源码跑一跑,这样能深刻的理解《大话设计模式这本书》,现在将整个过程整理好,方便别人也方便自己!

 

第十一章:无熟人难办事?——迪米特法则    (低耦合)

迪米特法则 :(Law of  Demeter, LoD):一个软件实体应当尽可能少地与其他实体发生相互作用。

6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第1张图片

              问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类影响也越大。

        解决:一个软件实体应当尽可能少地与其他实体发生相互作用,迪米特法则可降低系统的耦合度,使类与类之间保持松散的耦合关系

优点:

缺点:

 

所使用的项目是:无

 

功能:

 

界面:

 

设计思路:

 

收获:

 

第十二章:牛市股票还会亏钱——外观模式

外观模式 :

优点:

缺点:

 

所使用的项目是:无

 

功能:

 

界面:

 

设计思路:

 

收获:

 6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第2张图片

附:

 

JAVA设计模式之门面模式(外观模式)

标签: 设计模式

2014-04-02 07:16 17125人阅读 评论(12) 收藏 举报

 分类:

设计模式(20) 

目录(?)[+]

医院的例子

  现代的软件系统都是比较复杂的,设计师处理复杂系统的一个常见方法便是将其“分而治之”,把一个系统划分为几个较小的子系统。如果把医院作为一个子系统,按照部门职能,这个系统可以划分为挂号、门诊、划价、化验、收费、取药等。看病的病人要与这些部门打交道,就如同一个子系统的客户端与一个子系统的各个类打交道一样,不是一件容易的事情。

  首先病人必须先挂号,然后门诊。如果医生要求化验,病人必须首先划价,然后缴费,才可以到化验部门做化验。化验后再回到门诊室。

 

6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第3张图片

 

 

上图描述的是病人在医院里的体验,图中的方框代表医院。

  解决这种不便的方法便是引进门面模式,医院可以设置一个接待员的位置,由接待员负责代为挂号、划价、缴费、取药等。这个接待员就是门面模式的体现,病人只接触接待员,由接待员与各个部门打交道。

 

6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第4张图片

 

 

门面模式的结构

  门面模式没有一个一般化的类图描述,最好的描述方法实际上就是以一个例子说明。

6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第5张图片

 由于门面模式的结构图过于抽象,因此把它稍稍具体点。假设子系统内有三个模块,分别是ModuleA、ModuleB和ModuleC,它们分别有一个示例方法,那么此时示例的整体结构图如下:

 

6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第6张图片

 

 

在这个对象图中,出现了两个角色:

  ●  门面(Facade)角色 :客户端可以调用这个角色的方法。此角色知晓相关的(一个或者多个)子系统的功能和责任。在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去。

  ●  子系统(SubSystem)角色 :可以同时有一个或者多个子系统。每个子系统都不是一个单独的类,而是一个类的集合(如上面的子系统就是由ModuleA、ModuleB、ModuleC三个类组合而成)。每个子系统都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另外一个客户端而已。

源代码

  子系统角色中的类:

[java] view plain copy  print?

  1. public class ModuleA {  
  2.     //示意方法  
  3.     public void testA(){  
  4.         System.out.println("调用ModuleA中的testA方法");  
  5.     }  
  6. }  

[java] view plain copy  print?

  1. public class ModuleB {  
  2.     //示意方法  
  3.     public void testB(){  
  4.         System.out.println("调用ModuleB中的testB方法");  
  5.     }  
  6. }  


 

[java] view plain copy  print?

  1. public class ModuleC {  
  2.     //示意方法  
  3.     public void testC(){  
  4.         System.out.println("调用ModuleC中的testC方法");  
  5.     }  
  6. }  


 门面角色类:

[java] view plain copy  print?

  1. public class Facade {  
  2.     //示意方法,满足客户端需要的功能  
  3.     public void test(){  
  4.         ModuleA a = new ModuleA();  
  5.         a.testA();  
  6.         ModuleB b = new ModuleB();  
  7.         b.testB();  
  8.         ModuleC c = new ModuleC();  
  9.         c.testC();  
  10.     }  
  11. }  

客户端角色类:

[java] view plain copy  print?

  1. public class Client {  
  2.   
  3.     public static void main(String[] args) {  
  4.           
  5.         Facade facade = new Facade();  
  6.         facade.test();  
  7.     }  
  8.   
  9. }  

 Facade类其实相当于A、B、C模块的外观界面,有了这个Facade类,那么客户端就不需要亲自调用子系统中的A、B、C模块了,也不需要知道系统内部的实现细节,甚至都不需要知道A、B、C模块的存在,客户端只需要跟Facade类交互就好了,从而更好地实现了客户端和子系统中A、B、C模块的解耦,让客户端更容易地使用系统。

 


 

门面模式的实现

  使用门面模式还有一个附带的好处,就是能够有选择性地暴露方法。一个模块中定义的方法可以分成两部分,一部分是给子系统外部使用的,一部分是子系统内部模块之间相互调用时使用的。有了Facade类,那么用于子系统内部模块之间相互调用的方法就不用暴露给子系统外部了。

  比如,定义如下A、B、C模块。

[java] view plain copy  print?

  1. public class Module {  
  2.     /** 
  3.      * 提供给子系统外部使用的方法 
  4.      */  
  5.     public void a1(){};  
  6.       
  7.     /** 
  8.      * 子系统内部模块之间相互调用时使用的方法 
  9.      */  
  10.     private void a2(){};  
  11.     private void a3(){};  
  12. }  


 

[java] view plain copy  print?

  1. public class ModuleB {  
  2.     /** 
  3.      * 提供给子系统外部使用的方法 
  4.      */  
  5.     public void b1(){};  
  6.       
  7.     /** 
  8.      * 子系统内部模块之间相互调用时使用的方法 
  9.      */  
  10.     private void b2(){};  
  11.     private void b3(){};  
  12. }  


 

[java] view plain copy  print?

  1. public class ModuleC {  
  2.     /** 
  3.      * 提供给子系统外部使用的方法 
  4.      */  
  5.     public void c1(){};  
  6.       
  7.     /** 
  8.      * 子系统内部模块之间相互调用时使用的方法 
  9.      */  
  10.     private void c2(){};  
  11.     private void c3(){};  
  12. }  


 

[java] view plain copy  print?

  1. public class ModuleFacade {  
  2.       
  3.     ModuleA a = new ModuleA();  
  4.     ModuleB b = new ModuleB();  
  5.     ModuleC c = new ModuleC();  
  6.     /** 
  7.      * 下面这些是A、B、C模块对子系统外部提供的方法 
  8.      */  
  9.     public void a1(){  
  10.         a.a1();  
  11.     }  
  12.     public void b1(){  
  13.         b.b1();  
  14.     }  
  15.     public void c1(){  
  16.         c.c1();  
  17.     }  
  18. }  

这样定义一个ModuleFacade类可以有效地屏蔽内部的细节,免得客户端去调用Module类时,发现一些不需要它知道的方法。比如a2()和a3()方法就不需要让客户端知道,否则既暴露了内部的细节,又让客户端迷惑。对客户端来说,他可能还要去思考a2()、a3()方法用来干什么呢?其实a2()和a3()方法是内部模块之间交互的,原本就不是对子系统外部的,所以干脆就不要让客户端知道。

一个系统可以有几个门面类

  在门面模式中,通常只需要一个门面类,并且此门面类只有一个实例,换言之它是一个单例类。当然这并不意味着在整个系统里只有一个门面类,而仅仅是说对每一个子系统只有一个门面类。或者说,如果一个系统有好几个子系统的话,每一个子系统都有一个门面类,整个系统可以有数个门面类。

为子系统增加新行为

  初学者往往以为通过继承一个门面类便可在子系统中加入新的行为,这是错误的。门面模式的用意是为子系统提供一个集中化和简化的沟通管道,而不能向子系统加入新的行为。比如医院中的接待员并不是医护人员,接待员并不能为病人提供医疗服务。

 

门面模式的优点

  门面模式的优点:

  ●  松散耦合

  门面模式松散了客户端与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护。

  ●  简单易用

  门面模式让子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟门面类交互就可以了。

  ●  更好的划分访问层次

  通过合理使用Facade,可以帮助我们更好地划分访问的层次。有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到门面中,这样既方便客户端使用,也很好地隐藏了内部的细节。


 

作者:jason0539

微博:http://weibo.com/2553717707

博客:http://blog.csdn.net/jason0539(转载请说明出处)

来源: http://blog.csdn.net/jason0539/article/details/22775311

 

 

第十三章:好菜每回味不同——建造者模式

 

建造者模式 :是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

 

顾名思义,builder的意思是建造者或者建筑工人,谈到建造自然会想到楼房。楼房是千差万别的,楼房的外形、层数、内部房间的数量、房间的装饰等等都不一样,但是对于建造者来说,抽象出来的建筑流程是确定的,往往建筑一座楼房包括下面的步骤:(1)打桩,建立基础(2)建立框架等。建造者模式的本质和建造楼房是一致的:即流程不变,但每个流程实现的具体细节则是经常变化的。建造者模式的好处就是保证了流程不会变化,流程即不会增加、也不会遗漏或者产生流程次序错误,这是非常重要的。我们熟知的楼歪歪事件,官方的解释就是由于先建立楼房后,再建设停车场造成的,这是典型的建造次序错乱。(看来这些人儿不知道建造者模式啊!!!)

来源: http://www.cnblogs.com/BeyondAnyTime/archive/2012/07/19/2599980.html

 

就如做法形成了标准,老干妈口味保持一致,但是各家饭馆的千叶豆腐口味确实不一。前者便是建造模式的好处。

 

优点:

1.使用建造者模式可以使客户端不必知道产品内部组成的细节。

2.具体的建造者类之间是相互独立的,对系统的扩展非常有利。

3.由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。

 

缺点:

 

所使用的项目是:造小人

 

功能:

 

界面:

 

设计思路:

 

收获:

建造者模式通常包括下面几个角色:

1. builder:给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。

2. ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建。 在建造过程完成后,提供产品的实例。

3. Director:调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。

4. Product:要创建的复杂对象。

  按照惯例,还是给出建造者模式的结构图

     6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第7张图片             

 

第十四章:老板回来,我不知道——观察者模式

观察者模式 :

优点:

缺点:

 

所使用的项目是:前台通知同事老板来了

 

功能:

 

界面:

 

设计思路:

 6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第8张图片

 

收获:

 6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第9张图片

 6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第10张图片

 

第十五章:就不能不换DB么?——抽象工厂模式

抽象工程模式:

 6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第11张图片

 6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第12张图片

优点:

缺点:

 

所使用的项目是:数据库

 

功能:

 

界面:

 

设计思路:

 6、大话设计模式--迪米特法则 、外观模式、建造者模式、观察者模式、抽象工厂模式_第13张图片

 

收获:

 

附:

 

JAVA设计模式之抽象工厂模式

标签: java设计模式工厂模式

2015-04-11 08:26 24815人阅读 评论(18) 收藏 举报

 分类:

设计模式(20) 

本文继续介绍23种设计模式系列之抽象工厂模式。

前面已经介绍过简单工厂模式和工厂方法模式,这里继续介绍第三种工厂模式-抽象工厂模式,还是以汽车的制造为例。

 

例子背景:

随着客户的要求越来越高,宝马车需要不同配置的空调和发动机等配件。于是这个工厂开始生产空调和发动机,用来组装汽车。这时候工厂有两个系列的产品:空调和发动机。宝马320系列配置A型号空调和A型号发动机,宝马230系列配置B型号空调和B型号发动机。

 

概念:

   抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。比如宝马320系列使用空调型号A和发动机型号A,而宝马230系列使用空调型号B和发动机型号B,那么使用抽象工厂模式,在为320系列生产相关配件时,就无需制定配件的型号,它会自动根据车型生产对应的配件型号A。

 

针对百度百科上对于抽象工厂模式的简介,结合本例如下:

 

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

 

抽象工厂模式代码

 产品类: 

 

[java] view plain copy  print?

  1. //发动机以及型号    
  2. public interface Engine {    
  3.   
  4. }    
  5. public class EngineA extends Engine{    
  6.     public EngineA(){    
  7.         System.out.println("制造-->EngineA");    
  8.     }    
  9. }    
  10. public class EngineBextends Engine{    
  11.     public EngineB(){    
  12.         System.out.println("制造-->EngineB");    
  13.     }    
  14. }    
  15.   
  16. //空调以及型号    
  17. public interface Aircondition {    
  18.   
  19. }    
  20. public class AirconditionA extends Aircondition{    
  21.     public AirconditionA(){    
  22.         System.out.println("制造-->AirconditionA");    
  23.     }    
  24. }    
  25. public class AirconditionB extends Aircondition{    
  26.     public AirconditionB(){    
  27.         System.out.println("制造-->AirconditionB");    
  28.     }    
  29. }   

 


创建工厂类:

 

[java] view plain copy  print?

  1. //创建工厂的接口    
  2. public interface AbstractFactory {    
  3.     //制造发动机  
  4.     public Engine createEngine();  
  5.     //制造空调   
  6.     public Aircondition createAircondition();   
  7. }    
  8.   
  9.   
  10. //为宝马320系列生产配件    
  11. public class FactoryBMW320 implements AbstractFactory{    
  12.         
  13.     @Override    
  14.     public Engine createEngine() {      
  15.         return new EngineA();    
  16.     }    
  17.     @Override    
  18.     public Aircondition createAircondition() {    
  19.         return new AirconditionA();    
  20.     }    
  21. }    
  22. //宝马523系列  
  23. public class FactoryBMW523 implements AbstractFactory {    
  24.     
  25.      @Override    
  26.     public Engine createEngine() {      
  27.         return new EngineB();    
  28.     }    
  29.     @Override    
  30.     public Aircondition createAircondition() {    
  31.         return new AirconditionB();    
  32.     }    
  33.   
  34.   
  35. }   

 

 

客户:

 

[java] view plain copy  print?

  1. public class Customer {    
  2.     public static void main(String[] args){    
  3.         //生产宝马320系列配件  
  4.         FactoryBMW320 factoryBMW320 = new FactoryBMW320();    
  5.         factoryBMW320.createEngine();  
  6.         factoryBMW320.createAircondition();  
  7.             
  8.         //生产宝马523系列配件    
  9.         FactoryBMW523 factoryBMW523 = new FactoryBMW523();    
  10.         factoryBMW320.createEngine();  
  11.         factoryBMW320.createAircondition();  
  12.     }    
  13. }  


关于抽象工厂模式与工厂方法模式的区别,这里就不说了,感觉多看几遍例子就能理解,还有很多提到的产品族、等级结构等概念,说了反而更难理解。

 

 

抽象工厂模式的起源

下面引用一段抽象工厂模式的起源:

 

抽象工厂模式的起源或者最早的应用,是用于创建分属于不同操作系统的视窗构建。比如:命令按键(Button)与文字框(Text)都是视窗构建,在UNIX操作系统的视窗环境和Windows操作系统的视窗环境中,这两个构建有不同的本地实现,它们的细节有所不同。

在每一个操作系统中,都有一个视窗构建组成的构建家族。在这里就是Button和Text组成的产品族。而每一个视窗构件都构成自己的等级结构,由一个抽象角色给出抽象的功能描述,而由具体子类给出不同操作系统下的具体实现。

可以发现在上面的产品类图中,有两个产品的等级结构,分别是Button等级结构和Text等级结构。同时有两个产品族,也就是UNIX产品族和Windows产品族。UNIX产品族由UNIX Button和UNIX Text产品构成;而Windows产品族由Windows Button和Windows Text产品构成。

系统对产品对象的创建需求由一个工程的等级结构满足,其中有两个具体工程角色,即UnixFactory和WindowsFactory。UnixFactory对象负责创建Unix产品族中的产品,而WindowsFactory对象负责创建Windows产品族中的产品。这就是抽象工厂模式的应用,抽象工厂模式的解决方案如下图:

显然,一个系统只能够在某一个操作系统的视窗环境下运行,而不能同时在不同的操作系统上运行。所以,系统实际上只能消费属于同一个产品族的产品。

在现代的应用中,抽象工厂模式的使用范围已经大大扩大了,不再要求系统只能消费某一个产品族了。

 

 

总结:

无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。

       所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。

 

作者:jason0539

博客:http://blog.csdn.net/jason0539(转载请说明出处)

来源: http://blog.csdn.net/jason0539/article/details/44976775

 

 

 

你可能感兴趣的:(设计模式)