免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 829 | 回复: 0
打印 上一主题 下一主题

探索產生物件的技巧(1)當心隨手New一下引發的衝擊效應 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-09-18 11:12 |只看该作者 |倒序浏览

在程式設計裡,資訊不流通是一件好事。因為一個類別知道的資訊越少,就越不會因為資訊的改變而受到影響。
在物件導向程式設計中,倚靠的是封裝資料及行為的物件,透過物件所提供的機制以及彼此之間的相互合作,達成系統的需求。因此,產生類別物件就成了物件導向
程式中最基礎的動作。在常見的物件導向程式語言中,若要產生某類別的物件,最直接的方式莫過於透過像new之類的關鍵字,例如:
Object obj = new Object();
New的範圍越廣,影響的層面越大
然而,在實際的設計工作中,好的設計者及程式員,往往會運用更複雜的間接機制,產生所需類別的物件供系統之用。直接使用new語法產生物件,並直接運用會有什麼缺點?為什麼需要引入更複雜的間接機制?
先讓我們定義出在物件產生、運用的過程中會需要涉及到的角色:1.被產生者(The Created Class)2.產生者(Creator)3.用戶端(Client)。所謂的被產生者,就是會被產生的物件、產生者便是產生的物件,而用戶端,則是使用
物件的另一個物件。
最常見到的情況,便是用戶兼任產生者的情況。也就是說,因為需要動用到某類別的物件,所以便自己產生一個或若干個該物件,以便運用。例如(以Java寫成):

  
  LDAPAuthenticator authLDAP =
  new LDAPAuthenticator ();
  authLDAP.authenticate(id, passowrd);
  

如果單單只考慮這樣的應用情境,上述的程式碼是沒有什麼重大的缺陷。不過問題總在改變之後來臨。原始系統也許只需要以LDAP認證,但是也許突然
有一天,開發團隊被要求變更系統,讓系統可以允許多種認證的方式,包括讀取資料庫中的使用者帳號資料,或是以客製化方式認證。至於採用那一種認證方式,是 設定系統的組態決定。
設計者也許會考慮選擇提供多種不同認證方式的類別,然後在呼叫時,依據系統的組態設定值,決定究竟要運用那種認證方式,好比如下的寫法:

  
  boolean fAuthResult = false;
  if( authType == LDAP_AUTH )
  {
      LDAPAuthenticator authLDAP =
      new LDAPAuthenticator ();
      fAuthResult = authLDAP.authenticate
      (id, passowrd);
  }
  else if(authType == DB_AUTH )
  {
      DBAuthenticator authDB =
      new DBAuthenticator ();
      fAuthResult = authDB.authenticate
      (id, passowrd);
  }
  

但是,這樣的寫法存在一些問題。當你需要增加新的認證方式時,免不了必須修改程式碼。除了要新增類別之外,用戶端的程式也必須同步修改,才能夠將組態設定值,對映到新增的認證用類別,因而使得需求變更的影響層面更大。
知道的越少,就越不會被影響
倘若我們改用另一種寫法,針對認證功能制定出一個介面:

  
  public interface Authenticator
  {
     boolean authenticate
     (String id, String password);
  }
  

並為各種認證功能實作其類別,使各類別實作此一介面:

  
  class LDAPAuthenticator implements Authenticator { }
  class DBAuthenticator implements Authenticator { }
  class Cusomter1Authenticator implements Authenticator { }
  

利用另一個類別負責產生提供認證功能的類別:

  
  public class AuthenticatorCreator
  {
     public static Authenticator createAuthenticator() { }
  }
  

那麼需要使用認證功能的程式碼,就能夠寫成:

  
  Authenticator auth =
  AuthenticatorCreator.createAuthenticator();
  auth.authenticate(id, passowrd);
  

在這個新版的程式碼中,我們看到了一個重大的變化:用戶端並不知道自己究竟產生的物件其確切型別為何,只知道它實作了某一個介面。在這段程式碼中,絲毫看不到new的語法,因為我們拆散了原先合併在一塊的產生者與用戶端兩角色。
在這個版本中,我們將產生認證類別物件的工作,委派由另一個叫做AuthenticatorCreator的類別執行。所以對用戶端程式碼來說,
只需要知道(1)所有實作Authenticator的類別都提供了認證的功能(2)AuthenticatorCreator能夠回傳實作目前系統組態 所設定的認證方式類別。因此,用戶端的程式碼妥善地受到阻隔,因為它不需要知道系統組態目前的設定為何,也不需要知道如何對應各種認證功能設定與相對應實
作的類別,再者,它不需要知道系統究竟提供多少種認證的方式,而後續新增加認證的方式,也不會影響到用戶端程式碼。
上述的寫法,善用設計模式(Design Patterns)裡的「針對介面寫程式,而不要針對實作(Program to an interface, not an implementation)」。我們讓用戶端的程式碼存取的是認證的介面(Authenticator),而非存取各式認證的實作 (LDAPAuthenticator、DB Authenticator、Customer1 Authenticator…)。這使得用戶端的程式碼,對真正的實作為何,一無所悉。
在程式設計裡,資訊不流通是一件好事。一個類別知道的資訊越少,就越不會因為資訊的改變而被影響。
此外,用戶端除了它不知道自己所使用的究竟是什麼之外,它甚至不知道本身所使用的物件,究竟是如何產生出來的!這就是將產生者的角色,自用戶端程式碼中拆開之後得到的好處。
封裝與隱藏產生物件的邏輯,才能消除物件之間的相依性
不在用戶端程式碼中直接使用new,為的是封裝並隱藏產生物件的邏輯。而封裝與隱藏,為得是希望能夠消除用戶端程式和它所欲使用的物件之間的相依性,避免當用戶端所使用的物件改變時,會被影響。
許多人觀察到在各種不同的應用情境下,倘若將產生物件的動作,自用戶端程式碼中抽離,並以特定的方式產生,便能夠從中得到設計的好處。而這類的特定方式,就被整理設計模式裡所謂的「生成模式(Creational Patterns)」。
各種不同的生成模式,其實都在告訴我們,各種間接產生物件的方式、在不同的應用情境下加以運用,可以得到什麼好處。在後續的介紹中,我將不拘泥於特定的生成模式,而將主題放在產生物件的方式,探討相關的諸般技巧。
《作者簡介》王建興
清華大學資訊工程系的博士研究生,研究興趣包括電腦網路、點對點網路、分散式網路管理、以及行動式代理人,專長則是Internet應用系統的開發。曾參與過的開發專案性質十分廣泛而且不同,從ERP、PC Game到P2P網路電話都在他的涉獵範圍之內。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/32667/showart_384275.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP