熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

設計模式分解java(2)

2013-11-23 19:52:04  來源: Java高級技術 

  當然也可以結合工廠模式來創建AbstractSpoon實例

  在Java中Prototype模式變成clone()方法的使用由於Java的純潔的面向對象特性

  使得在Java中使用設計模式變得很自然兩者已經幾乎是渾然一體了這反映在很多模式上如Interator遍歷模式

  /***/

  創建模式Builder

  Builder模式定義:

  將一個復雜對象的構建與它的表示分離使得同樣的構建過程可以創建不同的表示

  Builder模式是一步一步創建一個復雜的對象它允許用戶可以只通過指定復雜對象的類型和內容就可以構建它們

  用戶不知道內部的具體構建細節Builder模式是非常類似抽象工廠模式

  細微的區別大概只有在反復使用中才能體會到

  為何使用?

  是為了將構建復雜對象的過程和它的部件解耦注意: 是解耦過程和部件

  因為一個復雜的對象不但有很多大量組成部分如汽車有很多部件:車輪 方向盤 發動機還有各種小零件等等

  部件很多但遠不止這些如何將這些部件裝配成一輛汽車這個裝配過程也很復雜(需要很好的組裝技術)

  Builder模式就是為了將部件和組裝過程分開

  如何使用?

  首先假設一個復雜對象是由多個部件組成的Builder模式是把復雜對象的創建和部件的創建分別開來

  分別用Builder類和Director類來表示

  首先需要一個接口它定義如何創建復雜對象的各個部件:

  public interface Builder {

  //創建部件A  比如創建汽車車輪

  void buildPartA();

  //創建部件B 比如創建汽車方向盤

  void buildPartB();

  //創建部件C 比如創建汽車發動機

  void buildPartC();

  //返回最後組裝成品結果 (返回最後裝配好的汽車)

  //成品的組裝過程不在這裡進行而是轉移到下面的Director類中進行

  //從而實現了解耦過程和部件

  Product getResult();

  }

  用Director構建最後的復雜對象而在上面Builder接口中封裝的是如何創建一個個部件

  (復雜對象是由這些部件組成的)也就是說Director的內容是如何將部件最後組裝成成品:

  public class Director {

  private Builder builder;

  public Director( Builder builder ) {

  thisbuilder = builder;

  }

  // 將部件partA partB partC最後組成復雜對象

  //這裡是將車輪 方向盤和發動機組裝成汽車的過程

  public void construct() {

  builderbuildPartA();

  builderbuildPartB();

  builderbuildPartC();

  }

  }

  Builder的具體實現ConcreteBuilder:

  通過具體完成接口Builder來構建或裝配產品的部件;

  定義並明確它所要創建的是什麼具體東西;

  提供一個可以重新獲取產品的接口:

  public class ConcreteBuilder implements Builder {

  Part partA partB partC;

  public void buildPartA() {

  //這裡是具體如何構建partA的代碼

  };

  public void buildPartB() {

  //這裡是具體如何構建partB的代碼

  };

  public void buildPartC() {

  //這裡是具體如何構建partB的代碼

  };

  public Product getResult() {

  //返回最後組裝成品結果

  };

  }

  復雜對象:產品Product:

  public interface Product { }

  復雜對象的部件:

  public interface Part { }

  我們看看如何調用Builder模式:

  ConcreteBuilder builder = new ConcreteBuilder();

  Director director = new Director( builder );

  nstruct();

  Product product = buildergetResult();

  Builder模式的應用

  在Java實際使用中我們經常用到(Pool)的概念當資源提供者無法提供足夠的資源

  並且這些資源需要被很多用戶反復共享時就需要使用池

  實際是一段內存當池中有一些復雜的資源的斷肢(比如數據庫的連接池也許有時一個連接會中斷)

  如果循環再利用這些斷肢將提高內存使用效率提高池的性能

  修改Builder模式中Director類使之能診斷斷肢斷在哪個部件上再修復這個部件

  /***/

  創建模式Singleton

  定義:

  Singleton模式主要作用是保證在Java應用程序中一個類Class只有一個實例存在

  在很多操作中比如建立目錄 數據庫連接都需要這樣的單線程操作

  還有 singleton能夠被狀態化; 這樣多個單態類在一起就可以作為一個狀態倉庫一樣向外提供服務比如你要論壇中的帖子計數器每次浏覽一次需要計數單態類能否保持住這個計數並且能synchronize的安全自動加如果你要把這個數字永久保存到數據庫你可以在不修改單態接口的情況下方便的做到

  另外方面Singleton也能夠被無狀態化提供工具性質的功能

  Singleton模式就為我們提供了這樣實現的可能使用Singleton的好處還在於可以節省內存因為它限制了實例的個數有利於Java垃圾回收(garbage collection)

  我們常常看到工廠模式中類裝入器(class loader)中也用Singleton模式實現的因為被裝入的類實際也屬於資源

  如何使用?

  一般Singleton模式通常有幾種形式:

  public class Singleton {

  private Singleton(){}

  //在自己內部定義自己一個實例是不是很奇怪?

  //注意這是private 只供內部調用

  private static Singleton instance = new Singleton();

  //這裡提供了一個供外部訪問本class的靜態方法可以直接訪問

  public static Singleton getInstance() {

  return instance;

  }

  }

  第二種形式:

  public class Singleton {

  private static Singleton instance = null;

  public static synchronized Singleton getInstance() {

  //這個方法比上面有所改進不用每次都進行生成對象只是第一次

  //使用時生成實例提高了效率!

  if (instance==null)

  instance=new Singleton();

  return instance;   }

  }

  使用SingletongetInstance()可以訪問單態類

  上面第二中形式是lazy initialization也就是說第一次調用時初始Singleton以後就不用再生成了

  注意到lazy initialization形式中的synchronized這個synchronized很重要如果沒有synchronized那麼使用 getInstance()是有可能得到多個Singleton實例關於lazy initialization的Singleton有很多涉及doublechecked locking (DCL)的討論有興趣者進一步研究

  一般認為第一種形式要更加安全些

  使用Singleton注意事項

  有時在某些情況下使用Singleton並不能達到Singleton的目的如有多個Singleton對象同時被不同的類裝入器裝載在EJB這樣的分布式系統中使用也要注意這種情況因為EJB是跨服務器跨JVM的

  我們以SUN公司的寵物店源碼(Pet Store )的ServiceLocator為例稍微分析一下

  在Pet Store中ServiceLocator有兩種一個是EJB目錄下一個是WEB目錄下我們檢查這兩個ServiceLocator會發現內容差不多都是提供EJB的查詢定位服務可是為什麼要分開呢?仔細研究對這兩種ServiceLocator才發現區別在WEB中的 ServiceLocator的采取Singleton模式ServiceLocator屬於資源定位理所當然應該使用Singleton模式但是在EJB中Singleton模式已經失去作用所以ServiceLocator才分成兩種一種面向WEB服務的一種是面向EJB服務的

  Singleton模式看起來簡單使用方法也很方便但是真正用好是非常不容易需要對Java的類 線程 內存等概念有相當的了解

  /***/

  結構模式Facade

  Facade的定義: 為子系統中的一組接口提供一個一致的界面

  Facade一個典型應用就是數據庫JDBC的應用如下例對數據庫的操作:

  public class DBCompare {

  Connection conn = null;

  PreparedStatement prep = null;

  ResultSet rset = null;

  try {

  ClassforName( <driver> )newInstance();

  conn = DriverManagergetConnection( <database> );

  String sql = SELECT * FROM <table> WHERE <column name> = ?;

  prep = connprepareStatement( sql );

  prepsetString( <column value> );

  rset = prepexecuteQuery();

  if( rsetnext() ) {

  Systemoutprintln( rsetgetString( <column name ) );

  }

  } catch( SException e ) {

  eprintStackTrace();

  } finally {

  rsetclose();

  prepclose();

  connclose();

  }

  }

  上例是Jsp中最通常的對數據庫操作辦法

  在應用中經常需要對數據庫操作每次都寫上述一段代碼肯定比較麻煩需要將其中不變的部分提煉出來做成一個接口這就引入了facade外觀對象如果以後我們更換ClassforName中的<driver>也非常方便比如從Mysql數據庫換到Oracle數據庫只要更換 facade接口中的driver就可以

  我們做成了一個Facade接口使用該接口上例中的程序就可以更改如下:

  public class DBCompare {

  String sql = SELECT * FROM <table> WHERE <column name> = ?;

  try {

  Mysql msql=new mysql(sql);

  prepsetString( <column value> );

  rset = prepexecuteQuery();

  if( rsetnext() ) {

  Systemoutprintln( rsetgetString( <column name ) );

  }

  } catch( SException e ) {

  eprintStackTrace();

  } finally {

  mysqlclose();

  mysql=null;

  }

  }

  可見非常簡單所有程序對數據庫訪問都是使用改接口降低系統的復雜性增加了靈活性

  如果我們要使用連接池也只要針對facade接口修改就可以

  facade實際上是個理順系統間關系降低系統間耦合度的一個常用的辦法

  也許你已經不知不覺在使用盡管不知道它就是facade

  /***/

  結構模式Proxy

  Proxy是比較有用途的一種模式而且變種較多應用場合覆蓋從小結構到整個系統的大結構

  Proxy是代理的意思我們也許有代理服務器等概念

  代理概念可以解釋為:在出發點到目的地之間有一道中間層意為代理

  設計模式中定義: 為其他對象提供一種代理以控制對這個對象的訪問

  為什麼要使用Proxy?

  授權機制 不同級別的用戶對同一對象擁有不同的訪問權利

  如Jive論壇系統中就使用Proxy進行授權機制控制

  訪問論壇有兩種人:注冊用戶和游客(未注冊用戶)

  Jive中就通過類似ForumProxy這樣的代理來控制這兩種用戶對論壇的訪問權限

  某個客戶端不能直接操作到某個對象但又必須和那個對象有所互動

  舉例兩個具體情況:

  ()如果那個對象是一個是很大的圖片需要花費很長時間才能顯示出來

  那麼當這個圖片包含在文檔中時使用編輯器或浏覽器打開這個文檔打開文檔必須很迅速

  不能等待大圖片處理完成這時需要做個圖片Proxy來代替真正的圖片

  ()如果那個對象在Internet的某個遠端服務器上

  直接操作這個對象因為網絡速度原因可能比較慢那我們可以先用Proxy來代替那個對象

  總之原則是對於開銷很大的對象只有在使用它時才創建這個原則可以為我們節省很多寶貴的Java內存

  所以有些人認為Java耗費資源內存我以為這和程序編制思路也有一定的關系

  如何使用Proxy?

  以Jive論壇系統為例訪問論壇系統的用戶有多種類型:注冊普通用戶 論壇管理者 系統管理者 游客

  注冊普通用戶才能發言;論壇管理者可以管理他被授權的論壇;系統管理者可以管理所有事務等

  這些權限劃分和管理是使用Proxy完成的

  Forum是Jive的核心接口在Forum中陳列了有關論壇操作的主要行為如論壇名稱

  論壇描述的獲取和修改帖子發表刪除編輯等

  在ForumPermissions中定義了各種級別權限的用戶:

  public class ForumPermissions implements Cacheable {

  /** Permission to read object*/

  public static final int READ = ;

  /** Permission to administer the entire sytem*/

  public static final int SYSTEM_ADMIN = ;

  /** Permission to administer a particular forum*/

  public static final int FORUM_ADMIN = ;

  /** Permission to administer a particular user*/

  public static final int USER_ADMIN = ;

  /** Permission to administer a particular group*/

  public static final int GROUP_ADMIN = ;

  /** Permission to moderate threads*/

  public static final int MODERATE_THREADS = ;

  /** Permission to create a new thread*/

  public static final int CREATE_THREAD = ;

  /** Permission to create a new message*/

  public static final int CREATE_MESSAGE = ;

  /** Permission to moderate messages*/

  public static final int MODERATE_MESSAGES = ;

  

  public boolean isSystemOrForumAdmin() {

  return (values[FORUM_ADMIN] || values[SYSTEM_ADMIN]);

  }

  

  }

  因此Forum中各種操作權限是和ForumPermissions定義的用戶級別有關系的

  作為接口Forum的實現:ForumProxy正是將這種對應關系聯系起來

  比如修改Forum的名稱只有論壇管理者或系統管理者可以修改代碼如下:

  public class ForumProxy implements Forum {

  private ForumPermissions permissions;

  private Forum forum;

  thisauthorization = authorization;

  public ForumProxy(Forum forum Authorization authorization

  ForumPermissions permissions)

  {

  thisforum = forum;

  thisauthorization = authorization;

  thispermissions = permissions;

  }

  

  public void setName(String name) throws UnauthorizedException

  ForumAlreadyExistsException

  {

  //只有是系統或論壇管理者才可以修改名稱

  if (permissionsisSystemOrForumAdmin()) {

  forumsetName(name);

  }

  else {

  throw new UnauthorizedException();

  }

  }

  

  }

  而DbForum才是接口Forum的真正實現以修改論壇名稱為例:

  public class DbForum implements Forum Cacheable {

  

  public void setName(String name) throws ForumAlreadyExistsException {

  

  thisname = name;

  //這裡真正將新名稱保存到數據庫中

  saveToDb();

  

  }

  

  }

  凡是涉及到對論壇名稱修改這一事件其他程序都首先得和ForumProxy打交道

  由ForumProxy決定是否有權限做某一樣事情ForumProxy是個名副其實的網關安全代理系統

  在平時應用中無可避免總要涉及到系統的授權或安全體系不管你有無意識的使用Proxy實際你已經在使用Proxy了


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27593.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.