接下来我们看看结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中适配器模式主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。其中的对象的适配器模式是各种结构型模式的起源。
  一、适配器模式 
适配器模式主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。
适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。有点抽象,我们来看看详细的内容。
  1.1、类的适配器模式 
类的适配器模式核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口是Targetable,通过Adapter类,将Source的功能扩展到Targetable里。
1 2 3 4 5 6 7 package  com.model.structure;  public  class  Source   {    public  void  method1 ()   {           System.out.println("this is original method!" );       }   } 
 
1 2 3 4 5 6 7 8 9 package  com.model.structure;  public  interface  Targetable   {         public  void  method1 ()  ;            public  void  method2 ()  ; } 
 
1 2 3 4 5 6 7 package  com.model.structure;  public  class  Adapter  extends  Source  implements  Targetable   {    public  void  method2 ()   {         System.out.println("this is the targetable method!" );     } } 
 
1 2 3 4 5 6 7 8 9 package  com.model.structure;  public  class  AdapterTest   {    public  static  void  main (String[] args)   {         Targetable target = new  Adapter();         target.method1();         target.method2();     } } 
 
AdapterTest的运行结果:
1 2 this  is original method!this  is the targetable method!
 
  1.2、对象的适配器模式 
对象的适配器模式的基本思路和类的适配器模式相同,只是将Adapter类作修改成Wrapper,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package  com.model.structure;  public  class  Wrapper  implements  Targetable   {      private  Source source;       public  Wrapper (Source source)   {         super ();         this .source = source;     }       @Override      public  void  method2 ()   {         System.out.println("this is the targetable method!" );     }       @Override      public  void  method1 ()   {         source.method1();     } } 
 
1 2 3 4 5 6 7 8 9 10 package  com.model.structure;  public  class  AdapterTest   {    public  static  void  main (String[] args)   {         Source source = new  Source();         Targetable target = new  Wrapper(source);         target.method1();         target.method2();     } } 
 
运行结果跟类的适配器模式例子的一样。
  1.3、接口的适配器模式 
接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行了。
这里看文字描述已经试够清楚的了,因此就不贴代码实例了。
  二、装饰模式 
装饰模式:在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
装饰模式的特点:
(1) 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。 
(2) 装饰对象包含一个真实对象的引用(reference) 
(3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。 
(4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。继承不能做到这一点,继承的功能是静态的,不能动态增删。
具体看看代码实例
1 2 3 4 5 package  com.model.structure;  public  interface  Sourceable   {    public  void  method ()  ; } 
 
1 2 3 4 5 6 7 8 9 package  com.model.structure;  public  class  Source  implements  Sourceable   {      @Override      public  void  method ()   {         System.out.println("the original method!" );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package  com.model.structure;  public  class  Decorator  implements  Sourceable   {      private  Sourceable source;       public  Decorator (Sourceable source)   {         super ();         this .source = source;     }       @Override      public  void  method ()   {         System.out.println("before decorator!" );         source.method();         System.out.println("after decorator!" );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package  com.model.structure;  public  class  DecoratorTest   {      public  static  void  main (String[] args)   {                                                               Sourceable source = new  Source();         Sourceable obj = new  Decorator(source);         obj.method();     } } 
 
运行结果:
1 2 3 before decorator! the original method! after decorator! 
 
  三、代理模式 
代理模式就是多一个代理类出来,替原对象进行一些操作。代理类就像中介,它比我们掌握着更多的信息。
具体看看代码实例。
1 2 3 4 5 package  com.model.structure;  public  interface  Sourceable   {    public  void  method ()  ; } 
 
1 2 3 4 5 6 7 8 9 package  com.model.structure;  public  class  Source  implements  Sourceable   {      @Override      public  void  method ()   {         System.out.println("the original method!" );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package  com.model.structure;  public  class  Proxy  implements  Sourceable   {      private  Source source;       public  Proxy ()   {         super ();         this .source = new  Source();     }       @Override      public  void  method ()   {         before();         source.method();         atfer();     }       private  void  atfer ()   {         System.out.println("after proxy!" );     }       private  void  before ()   {         System.out.println("before proxy!" );     } } 
 
1 2 3 4 5 6 7 8 9 package  com.model.structure;  public  class  ProxyTest   {      public  static  void  main (String[] args)   {         Sourceable source = new  Proxy();         source.method();     } } 
 
运行结果:
1 2 3 before proxy! the original method! after proxy! 
 
补充:(代理模式看起来很像装饰器模式。
对装饰器模式来说,装饰者(decorator)和被装饰者(decoratee)都实现同一个 接口。对代理模式来说,代理类(proxy class)和真实处理的类(real class)都实现同一个接口。
此外,不论我们使用哪一个模式,都可以很容易地在真实对象的方法前面或者后面加上自定义的方法。
然而,实际上,在装饰器模式和代理模式之间还是有很多差别的。装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。
我们可以用另外一句话来总结这些差别:使用代理模式,代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造。 )
  四、外观模式 
外观模式是为了解决类与类之间的依赖关系的,像spring一样,可以将类和类之间的关系配置到配置文件中,而外观模式就是将他们的关系放在一个Facade类中,降低了类类之间的耦合度,该模式中没有涉及到接口。
我们以一个计算机的启动过程为例,看看如下的代码:
1 2 3 4 5 6 7 8 9 10 11 12 package  com.model.structure;  public  class  CPU   {      public  void  startup ()   {         System.out.println("cpu startup!" );     }       public  void  shutdown ()   {         System.out.println("cpu shutdown!" );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 package  com.model.structure;  public  class  Disk   {      public  void  startup ()   {         System.out.println("disk startup!" );     }       public  void  shutdown ()   {         System.out.println("disk shutdown!" );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 package  com.model.structure;  public  class  Memory   {      public  void  startup ()   {         System.out.println("memory startup!" );     }       public  void  shutdown ()   {         System.out.println("memory shutdown!" );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package  com.model.structure;  public  class  Computer   {      private  CPU cpu;     private  Memory memory;     private  Disk disk;       public  Computer ()   {         cpu = new  CPU();         memory = new  Memory();         disk = new  Disk();     }       public  void  startup ()   {         System.out.println("start the computer!" );         cpu.startup();         memory.startup();         disk.startup();         System.out.println("start computer finished!" );     }       public  void  shutdown ()   {         System.out.println("begin to close the computer!" );         cpu.shutdown();         memory.shutdown();         disk.shutdown();         System.out.println("computer closed!" );     } } 
 
1 2 3 4 5 6 7 8 9 10 package  com.model.structure;  public  class  User   {      public  static  void  main (String[] args)   {         Computer computer = new  Computer();         computer.startup();         computer.shutdown();     } } 
 
运行结果:
1 2 3 4 5 6 7 8 9 10 start the computer! cpu startup! memory startup! disk startup! start computer finished! begin to close the computer! cpu shutdown! memory shutdown! disk shutdown! computer closed! 
 
  五、桥接模式 
在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。
在提出桥梁模式的时候指出,桥梁模式的用意是”将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化”。这句话有三个关键词,也就是抽象化、实现化和脱耦。
抽象化:存在于多个实体中的共同的概念性联系,就是抽象化。作为一个过程,抽象化就是忽略一些信息,从而把不同的实体当做同样的实体对待。 
实现化:抽象化给出的具体实现,就是实现化。 
脱耦:所谓耦合,就是两个实体的行为的某种强关联。而将它们的强关联去掉,就是耦合的解脱,或称脱耦。在这里,脱耦是指将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联。
下面我们来看看代码实例:
1 2 3 4 5 package  com.model.structure;  public  interface  Driver   {      public  void  connect ()  ;   } 
 
1 2 3 4 5 6 7 8 9 package  com.model.structure;  public  class  MysqlDriver  implements  Driver   {      @Override      public  void  connect ()   {         System.out.println("connect mysql done!" );     } } 
 
1 2 3 4 5 6 7 8 9 package  com.model.structure;  public  class  DB2Driver  implements  Driver   {      @Override      public  void  connect ()   {         System.out.println("connect db2 done!" );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package  com.model.structure;  public  abstract  class  DriverManager   {      private  Driver driver;       public  void  connect ()   {         driver.connect();     }       public  Driver getDriver ()   {         return  driver;     }       public  void  setDriver (Driver driver)   {         this .driver = driver;     } } 
 
1 2 3 4 5 6 7 8 package  com.model.structure;  public  class  MyDriverManager  extends  DriverManager   {      public  void  connect ()   {         super .connect();     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package  com.model.structure;  public  class  Client   {      public  static  void  main (String[] args)   {           DriverManager driverManager = new  MyDriverManager();         Driver driver1 = new  MysqlDriver();         driverManager.setDriver(driver1);         driverManager.connect();           Driver driver2 = new  DB2Driver();         driverManager.setDriver(driver2);         driverManager.connect();     } } 
 
执行结果:
1 2 connect mysql done! connect db2 done! 
 
如果看完代码实例还不是很理解,我们想想如下两个维度扩展:(1)假设我想加一个OracleDriver,这是一个维度,很好理解,不多解释。(2)假设我们想在连接前后固定输出点什么,我们只需要加一个MyDriverManager2,代码如下:
1 2 3 4 5 6 7 8 9 10 11 package  com.model.structure;  public  class  MyDriverManager2  extends  DriverManager   {      public  void  connect ()   {         System.out.println("before connect" );         super .connect();         System.out.println("after connect" );     }   } 
 
再将Client代码中的MyDriverManager 改成 MyDriverManager2 ,执行结果如下:
1 2 3 4 5 6 before connect connect mysql done! after connect before connect connect db2 done! after connect 
 
  六、组合模式 
组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。掌握组合模式的重点是要理解清楚 “部分/整体” 还有 ”单个对象“ 与 “组合对象” 的含义。
组合模式让你可以优化处理递归或分级数据结构。
《设计模式》:将对象组合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
涉及角色:
Component:是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
Leaf:在组合中表示叶子结点对象,叶子结点没有子结点。
Composite:定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。
比如现实中公司内各部门的层级关系,请看代码:
Component:是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package  com.model.structure;  public  abstract  class  Company   {      private  String name;       public  Company ()   {     }       public  Company (String name)   {         super ();         this .name = name;     }       public  String getName ()   {         return  name;     }       public  void  setName (String name)   {         this .name = name;     }       protected  abstract  void  add (Company company)  ;       protected  abstract  void  romove (Company company)  ;       protected  abstract  void  display (int  depth)  ;   } 
 
Composite:定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package  com.model.structure;  import  java.util.ArrayList;import  java.util.List;  public  class  ConcreteCompany  extends  Company   {      private  List<Company> cList;       public  ConcreteCompany ()   {         cList = new  ArrayList();     }       public  ConcreteCompany (String name)   {         super (name);         cList = new  ArrayList();     }       @Override      protected  void  add (Company company)   {         cList.add(company);     }       @Override      protected  void  display (int  depth)   {           StringBuilder sb = new  StringBuilder("" );         for  (int  i = 0 ; i < depth; i++) {             sb.append("-" );         }         System.out.println(new  String(sb) + this .getName());         for  (Company c : cList) {             c.display(depth + 2 );         }     }       @Override      protected  void  romove (Company company)   {         cList.remove(company);     } } 
 
Leaf:在组合中表示叶子结点对象,叶子结点没有子结点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package  com.model.structure;  public  class  HRDepartment  extends  Company   {    public  HRDepartment (String name)   {         super (name);     }       @Override      protected  void  add (Company company)   {     }       @Override      protected  void  display (int  depth)   {         StringBuilder sb = new  StringBuilder("" );         for  (int  i = 0 ; i < depth; i++) {             sb.append("-" );         }         System.out.println(new  String(sb) + this .getName());     }       @Override      protected  void  romove (Company company)   {     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package  com.model.structure;  public  class  FinanceDepartment  extends  Company   {    public  FinanceDepartment (String name)   {         super (name);     }       @Override      protected  void  add (Company company)   {     }       @Override      protected  void  display (int  depth)   {         StringBuilder sb = new  StringBuilder("" );         for  (int  i = 0 ; i < depth; i++) {             sb.append("-" );         }         System.out.println(new  String(sb) + this .getName());     }       @Override      protected  void  romove (Company company)   {     } } 
 
Client:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package  com.model.structure;  public  class  Client   {    public  static  void  main (String[] args)   {         Company root = new  ConcreteCompany();         root.setName("北京总公司" );         root.add(new  HRDepartment("总公司人力资源部" ));         root.add(new  FinanceDepartment("总公司财务部" ));         Company shandongCom = new  ConcreteCompany("山东分公司" );         shandongCom.add(new  HRDepartment("山东分公司人力资源部" ));         shandongCom.add(new  FinanceDepartment("山东分公司账务部" ));         Company zaozhuangCom = new  ConcreteCompany("枣庄办事处" );         zaozhuangCom.add(new  FinanceDepartment("枣庄办事处财务部" ));         zaozhuangCom.add(new  HRDepartment("枣庄办事处人力资源部" ));         Company jinanCom = new  ConcreteCompany("济南办事处" );         jinanCom.add(new  FinanceDepartment("济南办事处财务部" ));         jinanCom.add(new  HRDepartment("济南办事处人力资源部" ));         shandongCom.add(jinanCom);         shandongCom.add(zaozhuangCom);         Company huadongCom = new  ConcreteCompany("上海华东分公司" );         huadongCom.add(new  HRDepartment("上海华东分公司人力资源部" ));         huadongCom.add(new  FinanceDepartment("上海华东分公司账务部" ));         Company hangzhouCom = new  ConcreteCompany("杭州办事处" );         hangzhouCom.add(new  FinanceDepartment("杭州办事处财务部" ));         hangzhouCom.add(new  HRDepartment("杭州办事处人力资源部" ));         Company nanjingCom = new  ConcreteCompany("南京办事处" );         nanjingCom.add(new  FinanceDepartment("南京办事处财务部" ));         nanjingCom.add(new  HRDepartment("南京办事处人力资源部" ));         huadongCom.add(hangzhouCom);         huadongCom.add(nanjingCom);         root.add(shandongCom);         root.add(huadongCom);         root.display(0 );     } } 
 
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 北京总公司 --总公司人力资源部 --总公司财务部 --山东分公司 ----山东分公司人力资源部 ----山东分公司账务部 ----济南办事处 ------济南办事处财务部 ------济南办事处人力资源部 ----枣庄办事处 ------枣庄办事处财务部 ------枣庄办事处人力资源部 --上海华东分公司 ----上海华东分公司人力资源部 ----上海华东分公司账务部 ----杭州办事处 ------杭州办事处财务部 ------杭州办事处人力资源部 ----南京办事处 ------南京办事处财务部 ------南京办事处人力资源部 
 
  七、享元模式 
享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。
一提到共享池,我们很容易联想到Java里面的JDBC连接池,想想每个连接的特点,我们不难总结出:适用于作共享的一些个对象,他们有一些共有的属性,就拿数据库连接池来说,url、driverClassName、username、password及dbname,这些属性对于每个连接来说都是一样的,所以就适合用享元模式来处理,建一个工厂类,将上述类似属性作为内部数据,其它的作为外部数据,在方法调用时,当做参数传进来,这样就节省了空间,减少了实例的数量。
看下数据库连接池的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package  com.model.structure;  import  java.sql.Connection;import  java.sql.DriverManager;import  java.sql.SQLException;import  java.util.Vector;  public  class  ConnectionPool   {      private  Vector<Connection> pool;            private  String url = "jdbc:mysql://localhost:3306/test" ;     private  String username = "root" ;     private  String password = "root" ;     private  String driverClassName = "com.mysql.jdbc.Driver" ;       private  int  poolSize = 100 ;     private  static  ConnectionPool instance = null ;     Connection conn = null ;            private  ConnectionPool ()   {         pool = new  Vector<Connection>(poolSize);           for  (int  i = 0 ; i < poolSize; i++) {             try  {                 Class.forName(driverClassName);                 conn = DriverManager.getConnection(url, username, password);                 pool.add(conn);             } catch  (ClassNotFoundException e) {                 e.printStackTrace();             } catch  (SQLException e) {                 e.printStackTrace();             }         }     }            public  synchronized  void  release ()   {         pool.add(conn);     }            public  synchronized  Connection getConnection ()   {         if  (pool.size() > 0 ) {             Connection conn = pool.get(0 );             pool.remove(conn);             return  conn;         } else  {             return  null ;         }     } } 
 
通过连接池的管理,实现了数据库连接的共享,不需要每一次都重新创建连接,节省了数据库重新创建的开销,提升了系统的性能!
原文:http://blog.csdn.net/u013142781/article/details/50821155