成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

對(duì)象設(shè)計(jì)要考慮有效范圍

hatlonely / 2507人閱讀

摘要:另載于現(xiàn)代對(duì)象設(shè)計(jì)主張組合優(yōu)于繼承。對(duì)象的有效范圍,是指對(duì)象從創(chuàng)建到丟棄不再引用的這段時(shí)間,不包括等待被銷毀的時(shí)間。對(duì)于繼承也是同理,父類和子類應(yīng)當(dāng)有相同的有效范圍。同理,級(jí)的對(duì)象不要持有級(jí)的對(duì)象。

另載于 http://www.qingjingjie.com/blogs/9

現(xiàn)代對(duì)象設(shè)計(jì)主張“組合優(yōu)于繼承”。總之無(wú)論組合還是繼承,對(duì)象都成了涉及多個(gè)類的復(fù)合結(jié)構(gòu)。

“對(duì)象的有效范圍”,是指對(duì)象從創(chuàng)建到丟棄(不再引用)的這段時(shí)間,不包括等待被GC銷毀的時(shí)間。可以近似認(rèn)為是對(duì)象的生命期。

單例對(duì)象(Singleton)的有效范圍幾乎是整個(gè)應(yīng)用的開(kāi)啟時(shí)間,Socket的有效范圍通常是網(wǎng)絡(luò)連接的持續(xù)時(shí)間,而一個(gè)臨時(shí)的Integer則可能瞬間就被丟棄了。Let"s 注意,不同范圍的對(duì)象/類,不能隨意地組合/繼承在一起。

1. 不同范圍的對(duì)象避免打包在一起

(代碼有點(diǎn)多,如果嫌煩可以跳過(guò)1.先看2.)

反面教材:我們來(lái)看一個(gè)客戶端程序,它通過(guò)socket與某個(gè)服務(wù)器保持通信,不斷發(fā)消息并收取響應(yīng)。

public class Communication {
  private Topic topic;
  private Socket socket;

  public Communication(String host, int port) {
    socket = new Socket(host, port);
  }
  public void close() {
    socket.close();
  }
  public void setTopic(Topic topic) {
    this.topic = topic;
  }
  public String sendReceive(String msg) {
    return sendRecv_(topic, msg);
  }
  private String sendRecv_(Topic topic, String msg) {
    ... // 具體處理
  }
}

我們有兩個(gè)主題(topic) A和B,以不同主題發(fā)的消息,服務(wù)器會(huì)做不同處理。我們一會(huì)兒用主題A發(fā)消息,一會(huì)用主題B發(fā)消息。代碼如下:

Communication comm = new Communication(host, port);
comm.setTopic(A);
comm.sendReceive("Hello!");
comm.sendReceive("How are you?");

comm.setTopic(B);
comm.sendReceive("Good morning!");
comm.sendReceive("Let"s begin");

comm.sendTopic(A);
comm.sendReceive("How old are you?");

切換來(lái)切換去,真麻煩。如果你不嫌麻煩,假設(shè)給Communication再加一個(gè)域"config",平均每發(fā)100條消息,要切換一次config,平均每發(fā)10條消息,要切換一次topic,還是交替進(jìn)行,煩不煩!

再想想,如果多個(gè)線程在使用comm對(duì)象呢? 呵呵呵,完蛋了。

Communication的有效范圍與socket一致,而topic的有效范圍就小于socket了,因此topic就不該放在這個(gè)類里。雖然sendReceive()可以少填一個(gè)參數(shù),看似方便,但是引發(fā)了更多麻煩。
對(duì)于繼承也是同理,父類和子類應(yīng)當(dāng)有相同的有效范圍。

所以還是這么寫(xiě)吧:

comm.sendReceive(A, "Hello!");
comm.sendReceive(A, "How are you?");
comm.sendReceive(B, "Good morning!");

稍微有點(diǎn)麻煩呢

或者這么寫(xiě):

class CommByTopic {
  private Communication comm;
  private Topic topic;
  // 構(gòu)造函數(shù)省略
  public String sendReceive(String msg) {
    return comm.sendReceive(topic, msg);
  }
}

CommByTopic onA = new CommByTopic(comm, A);
onA.sendReceive(msg);
onB.sendReceive(msg);

缺點(diǎn)是comm關(guān)閉后要注意不能繼續(xù)使用onA。所以不要長(zhǎng)時(shí)間持有onA對(duì)象,最好能局限在方法作用域內(nèi)。

或者試試簡(jiǎn)潔的lamda~

Lamda in Java 8:

Function onA = msg -> comm.sendReceive(A, msg);
onA.apply("Hello!");
onA.apply("How are you?");

Lamda in Scala:

val onA: String => String = comm.sendReceive(A, _)
onA("Hello!")
onA("How are you?")

// 柯里化的寫(xiě)法 val onA = comm.sendReceive(A) _
2. 大范圍對(duì)象不要持有小范圍對(duì)象

上面說(shuō)的comm就是大范圍對(duì)象,socket也是大范圍對(duì)象,topic是小范圍對(duì)象。它們生命長(zhǎng)短不同。

如果大范圍對(duì)象持有了小范圍對(duì)象,你就要疲于切換,甚至擔(dān)心線程安全性。反過(guò)來(lái),小范圍對(duì)象持有大范圍對(duì)象,就好了。當(dāng)然了,持有相同范圍的對(duì)象也是好的。

對(duì)運(yùn)行于IoC容器的程序尤其明顯。來(lái)溜一段基于Spring MVC的應(yīng)用代碼:

@Component
@Scope("singleton") //單例對(duì)象
public class Manager {
  @Autowired
  private Account account;

  public void freezeAccount() {
    account.freeze();
    merge(account);
  }
}

@Component
@Scope("request") //request范圍的對(duì)象
public class Account {
  ...
}

這樣的代碼在系統(tǒng)啟動(dòng)時(shí)就崩了,因?yàn)閍ccount還沒(méi)出現(xiàn)。就算你給Manager標(biāo)上@Lazy (延遲初始化),讓它在賬戶A發(fā)來(lái)請(qǐng)求時(shí)才初始化,它也只能正確處理這次的請(qǐng)求。下次賬戶B再來(lái)請(qǐng)求時(shí),它還是使用上次的A的account來(lái)操作,而不會(huì)用B的account。呵呵呵,完蛋了。
同理,session級(jí)的對(duì)象不要持有request級(jí)的對(duì)象。

對(duì)于Servlet和Filter也是如此,它們是近似于單例的對(duì)象,讓它們持有一些配置數(shù)據(jù)和常量就行了,如果讓它們持有當(dāng)前的userId,也很危險(xiǎn)。

再提醒一下,其實(shí)小范圍對(duì)象持有大范圍對(duì)象也不要濫用,一不小心就會(huì)讓對(duì)象承擔(dān)過(guò)多職責(zé),有過(guò)多依賴。設(shè)計(jì)要從職責(zé)出發(fā)。

結(jié)語(yǔ)

之所以要從“有效范圍”的角度談對(duì)象設(shè)計(jì)的問(wèn)題,就是想給大家提供一個(gè)明確可操作的分析視角,這可比“設(shè)計(jì)哲學(xué)”容易多了。

不過(guò)光會(huì)這個(gè)還不夠,知識(shí)要全面。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/64139.html

相關(guān)文章

  • 如何有效地同多個(gè)云提供商合作

    摘要:在同多個(gè)云提供商合作之前,請(qǐng)?jiān)u估他們?cè)谟?jì)算存儲(chǔ)和安全等方面的服務(wù)。企業(yè)必須在多個(gè)云供應(yīng)商中做出抉擇。在與多個(gè)云供應(yīng)商合作時(shí)有一些策略和技巧,能夠得到其優(yōu)點(diǎn)同時(shí)限制了重復(fù)勞動(dòng)和其他額外的工作。 在同多個(gè)云提供商合作之前,請(qǐng)?jiān)u估他們?cè)谟?jì)算、存儲(chǔ)和安全等方面的服務(wù)。企業(yè)必須在多個(gè)云供應(yīng)商中做出抉擇。亞馬遜網(wǎng)絡(luò)服務(wù)是行業(yè)巨頭,而微軟Azure則提供了一整套越來(lái)越有競(jìng)爭(zhēng)力的服務(wù)。還有谷歌云平臺(tái)對(duì)于那些...

    xavier 評(píng)論0 收藏0
  • 軟件測(cè)試剛?cè)胄斜乜矗?測(cè)試基本流程、測(cè)試用例全在這里

    摘要:從業(yè)務(wù)流程上,應(yīng)得到以下信息主流程是什么條件備選流程是什么數(shù)據(jù)流向是什么關(guān)鍵的判斷條件是什么測(cè)試用例設(shè)計(jì)完成以上兩步則可進(jìn)行測(cè)試用例設(shè)計(jì),功能測(cè)試用例,應(yīng)盡量考慮邊界異常性能的情況,以便發(fā)現(xiàn)更多的隱藏問(wèn)題。 為什么測(cè)試人員要參加需求分析?也就是進(jìn)行測(cè)試需求分析的目的是什么? 第一、把用戶需求...

    Cristalven 評(píng)論0 收藏0
  • 軟件測(cè)試肖sir__005測(cè)試用例設(shè)計(jì)方法(1)

    摘要:需要結(jié)合其他測(cè)試用例設(shè)計(jì)的方法進(jìn)行補(bǔ)充。比如邊界值邊界值在軟件中邊界值測(cè)試方法是發(fā)現(xiàn)錯(cuò)誤能力最強(qiáng)的一種。其中,原因是表示輸入條件,結(jié)果是對(duì)輸入執(zhí)行的一系列計(jì)算后得到的輸出。與取值或,表示某狀態(tài)不出現(xiàn),則表示某狀態(tài)出現(xiàn)。 ...

    gnehc 評(píng)論0 收藏0
  • 2017前端性能優(yōu)化清單

    摘要:性能最好具有可量化可監(jiān)測(cè)以及可改動(dòng)的特性。下文是一份年的前端性能優(yōu)化清單,闡述了作為前端開(kāi)發(fā)人員,為了確保反饋速度以及瀏覽器兼容性我們需要考慮的問(wèn)題。地圖設(shè)計(jì)的決定違背了性能理念,所以他在這份清單內(nèi)的順序有待考慮。 2017前端性能優(yōu)化清單 你開(kāi)始使用漸進(jìn)啟動(dòng)了么?是不是已經(jīng)使用過(guò)React和Angular中tree-shaking和code-splitting兩個(gè)工具?有沒(méi)有用過(guò)Br...

    verano 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<