<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      不要讓編寫set訪問器成為習慣

      在C#中寫一個類的時候,你會毫不猶豫地為類的每個字段(field)寫上get和set訪問器嗎?如果是在從前,我會這么做的,但現在知道,不能這么做。

      感覺許多很重要很經典的話都很短,往往看得懂,都以為自己理解了,但事實上并沒有完全理解,就像Set訪問器。剛開始學習C#的時候,就知道了訪問器,書上說了,把字段聲明為private,然后通過設置set訪問器來暴露它,是為了更好的封裝性,在設值的時候可以有更多的控制,這其實還是很好理解的,但就這“封裝”二字,我當時并非真正理解(其實現在也沒有真正理解,只能說相比以前理解得更深入些)。于是,我也就那么跟著書上做了,聲明一個private的字段,然后寫上setter,而setter中幾乎都是XXX = value,這雖然比直接用public公開字段要好,但其實還是沒有很好的“封裝”,在OOP中,我們不希望一個對象過多的訪問其它對象的數據,而是希望通過調用其它對象的某個方法,來達到自己的目的,用通俗的話說,就是一個對象只需要告訴其它某個對象要做成什么事情,比如去把水燒開了,把電視機關掉,而不關心他所吩咐的那個對象是如何完成事情的。所以,有許多字段,我們不應該為其提供set訪問器。

      舉個例子,一個客戶類Customer:
      public class Customer {
          private int id; //客戶ID
          private string name;
          //...
          public void Save() {
              //如果id大于0就更新數據庫中的客戶記錄,否則就往數據庫插入新記錄
          }
      }
      就說這Cutomer的id字段。假設一個客戶擁有一個惟一的ID,如果此時為id字段寫一個set訪問器,那程序員就可以隨時隨意地更改id,這是很容易犯錯的,比如把客戶A的id改成了數據庫中一個已有的客戶B的id(不是故意的),那一旦調用Save()時,這個客戶A的信息全給更新到客戶B上面去了,可怕吧?還有更糟的,就是此時可能程序看起來還一切正常,等將來出問題時,那就是大問題了!

      既然沒有了set訪問器,那自然就要提供一個帶id參數的構造方法:Customer(int id),這樣就可以在創建新客戶時指定id,一旦指定后就不能改。

      假設現在確實有更改一個客戶的id的需求,那要咋辦?我想可以通過提供一個SetId(int newId)的方法來實現。這會兒可能會有人想問:“前面不是說了盡量不要用set訪問器,你這來個SetId(int newId)方法,不就相當于set訪問器嗎?這不是前后矛盾了?”。我是這么認為的:首先,如果我是機器,那我就不會覺得set訪問器和SetXXX()方法有什么不同,反正都是將一個新值賦給一個字段并做些控制。但我覺得它們的區別更多的應該從語義的層面去看:set訪問器強調改變“數據”,而SetXXX()方法則強調改變數據的這個“操作”。就比如前面說的id,如果用set訪問器,那就容易出錯,如果是用SetId(int newId)呢?當程序員調用這個方法時,他很可能就會注意到,哦,現在我是在做“改變客戶id”的操作,那他就會更謹慎一些,出錯的機率也就更小(是更小,而不是說用了SetId(int newId)來替代set訪問器就能杜絕錯誤)。也就是說,set訪問器和SetId(int newId)的關鍵區別,是前者易使程序員犯錯(邏輯錯誤),而后者不會。尤其當時間久了以后,或者程序是作為類庫給別人使用的時候。如果是寫庫給別人用,我們就應該考慮讓一個水平不怎么樣的程序員也能用自己的庫輕松地寫出高質量的程序。

      同樣,get訪問器和GetXXX()方法也是有區別的,還是上面的那個例子,假設Cutomer加了一個IList<Order> orders字段,Order是訂單類,表示客戶的訂單(假設是網上商城的場景)。代碼類似下面:
      public class Customer {
          private IList<Order> orders;
          public IList<Order> Orders {
              get { //...  }
          }
      }
      我們不希望其它的對象能隨意修改orders列表,但又需要取出訂單列表來顯示,所以我們往往在“取訂單”時返回訂單列表的一個副本(我們可以通過提供AddOrder(Order order)方法來實現對訂單的添加等需要的操作。如果不是返回副本,而是直接返回訂單列表的引用:IList<Order> orders = customer.Orders,當orders這個引用散布在程序中時,訂單中的數據就可能會被錯誤更改,比如表現層中要對訂單進行過濾,把一個月以前的訂單剔除后再顯示,此時可能就會調用orders.Remove(XXX)來移除一個月前的元素,事實上我們只是希望在表現層顯示時剔除一個月前的元素,如果此時有另一個操作要保存Customer實例,保存Customer時同時保存了訂單信息,于是一個隱蔽的錯誤就產生了:訂單數據莫名的丟失。可怕的是它還不容易被馬上發現,等我們發現這個Bug時,可能就已經釀下大錯了),也就是說,get訪問器中要執行一個拷貝操作,這個操作是要損失性能的,如果要遍歷訂單,程序員很可能就會這么寫:
      for (int i = 0; i < customer.Orders.Count; i++) {  //...  }
      每循環一次,就得調用一下get訪問器,每調用一次get訪問器,就得執行整個訂單列表的拷貝操作,想想這有多損失性能。 但如果我們不提供get訪問器,而是提供GetOrders()方法的話,程序員可能就會在調用這個方法時注意到,哦,現在是做取訂單操作,這個操作會不會是返回訂單列表的拷貝呢?于是他查看了文檔,寫下了下面的代碼:
      IList<Order> orders = customer.Orders;
      for (int i = 0; i < orders.Count; i++) {  //...  }
      這段代碼的性能可要比上面那段好得多得多了。是不是說用GetOrders()方法后程序員就不會寫出下面這樣的代碼呢:
      for(int i = 0; i < customer.GetOrders().Count; i++) {  //...  }
      會的,但是我相信會這么寫代碼的人相比前者要少許多。

      所以,我覺得get訪問器和GetXXX()方法的區別還是要更多的從語義上來看。用最自然的方式,用最不容易讓類的使用者出錯的方式來設計類。

      總結一下,本文的觀點有兩:
      1. 不要想當然地為每個字段提供一個set訪問器;
      2. 區分get訪問器和getXXX()方法;
      posted @ 2008-11-28 18:40  水言木  閱讀(0)  評論(2)    收藏  舉報
      主站蜘蛛池模板: 亚洲国产美女精品久久久久| 日本久久久www成人免费毛片丨 | 无码一区二区三区久久精品| 亚洲欧美人成电影在线观看| 宜兰市| 粉嫩av蜜臀一区二区三区| 成人国产片视频在线观看| 好紧好滑好湿好爽免费视频| 狠狠色综合网站久久久久久久| 国产精品v片在线观看不卡| 亚洲精品日产AⅤ| 亚洲嫩模喷白浆在线观看| 永久免费在线观看蜜桃视频| 国精偷拍一区二区三区| 国产大片黄在线观看| 国内精品一区二区在线观看| 一区二区三区精品视频免费播放| 欧洲码亚洲码的区别入口| 最近中文字幕免费手机版| 4480yy亚洲午夜私人影院剧情| 亚洲第一狼人天堂网伊人| 午夜性刺激在线观看| 久久中文字幕国产精品| 亚洲中文字幕一区二区| 老司机午夜免费精品视频| 亚洲精品国产av成人网| 久青草国产在视频在线观看| 日本强好片久久久久久aaa| 欧美成人aaa片一区国产精品| 九九热精品免费在线视频| 少妇被粗大猛进进出出| 麻豆一区二区三区蜜桃免费| 男女爽爽无遮挡午夜视频| 亚洲欧美v国产蜜芽tv| 国产色悠悠在线免费观看| 韩国无码AV片午夜福利| 拜城县| 亚洲欧美中文字幕日韩一区二区| 亚洲国产成人精品福利无码| 阳泉市| Y111111国产精品久久久|