自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

理解軟件設(shè)計(jì)模式

開(kāi)發(fā) 后端
設(shè)計(jì)模式可以幫助消除冗余代碼。學(xué)習(xí)如何利用 Java 使用單例模式、工廠模式和觀察者模式。

 [[273480]]

設(shè)計(jì)模式可以幫助消除冗余代碼。學(xué)習(xí)如何利用 Java 使用單例模式、工廠模式和觀察者模式。

如果你是一名正在致力于計(jì)算機(jī)科學(xué)或者相關(guān)學(xué)科的程序員或者學(xué)生,很快,你將會(huì)遇到一條術(shù)語(yǔ) “軟件設(shè)計(jì)模式software design pattern”。根據(jù)維基百科,“軟件設(shè)計(jì)模式是在平常的軟件設(shè)計(jì)工作中所遭遇的問(wèn)題的一種通用的、可重復(fù)使用的解決方案”。我對(duì)該定義的理解是:當(dāng)在從事于一個(gè)編碼項(xiàng)目時(shí),你經(jīng)常會(huì)思考,“嗯,這里貌似是冗余代碼,我覺(jué)得是否能改變這些代碼使之更靈活和便于修改?”因此,你會(huì)開(kāi)始考慮怎樣分割那些保持不變的內(nèi)容和需要經(jīng)常改變的內(nèi)容。

設(shè)計(jì)模式是一種通過(guò)分割那些保持不變的部分和經(jīng)常變化的部分,讓你的代碼更容易修改的方法。

不出意外的話,每個(gè)從事編程項(xiàng)目的人都可能會(huì)有同樣的思考。特別是那些工業(yè)級(jí)別的項(xiàng)目,在那里通常工作著數(shù)十甚至數(shù)百名開(kāi)發(fā)者;協(xié)作過(guò)程表明必須有一些標(biāo)準(zhǔn)和規(guī)則來(lái)使代碼更加優(yōu)雅并適應(yīng)變化。這就是為什么我們有了 面向?qū)ο缶幊?/a>(OOP)和 軟件框架工具。設(shè)計(jì)模式有點(diǎn)類(lèi)似于 OOP,但它通過(guò)將變化視為自然開(kāi)發(fā)過(guò)程的一部分而進(jìn)一步發(fā)展?;旧?,設(shè)計(jì)模式利用了一些 OOP 的思想,比如抽象和接口,但是專(zhuān)注于改變的過(guò)程。

當(dāng)你開(kāi)始開(kāi)發(fā)項(xiàng)目時(shí),你經(jīng)常會(huì)聽(tīng)到這樣一個(gè)術(shù)語(yǔ)重構(gòu),它意味著通過(guò)改變代碼使它變得更優(yōu)雅和可復(fù)用;這就是設(shè)計(jì)模式耀眼的地方。當(dāng)你處理現(xiàn)有代碼時(shí)(無(wú)論是由其他人構(gòu)建還是你自己過(guò)去構(gòu)建的),了解設(shè)計(jì)模式可以幫助你以不同的方式看待事物,你將發(fā)現(xiàn)問(wèn)題以及改進(jìn)代碼的方法。

有很多種設(shè)計(jì)模式,其中單例模式、工廠模式和觀察者模式三種最受歡迎,在這篇文章中我將會(huì)一一介紹它們。

如何遵循本指南

無(wú)論你是一位有經(jīng)驗(yàn)的編程工作者還是一名剛剛接觸的新手,我想讓這篇教程讓每個(gè)人都很容易理解。設(shè)計(jì)模式概念并不容易理解,減少開(kāi)始旅程時(shí)的學(xué)習(xí)曲線始終是首要任務(wù)。因此,除了這篇帶有圖表和代碼片段的文章外,我還創(chuàng)建了一個(gè) GitHub 倉(cāng)庫(kù),你可以克隆倉(cāng)庫(kù)并在你的電腦上運(yùn)行這些代碼來(lái)實(shí)現(xiàn)這三種設(shè)計(jì)模式。你也可以觀看我創(chuàng)建的 YouTube視頻。

必要條件

如果你只是想了解一般的設(shè)計(jì)模式思想,則無(wú)需克隆示例項(xiàng)目或安裝任何工具。但是,如果要運(yùn)行示例代碼,你需要安裝以下工具:

  • Java 開(kāi)發(fā)套件(JDK):我強(qiáng)烈建議使用 OpenJDK。
  • Apache Maven:這個(gè)簡(jiǎn)單的項(xiàng)目使用 Apache Maven 構(gòu)建;好的是許多 IDE 自帶了Maven。
  • 交互式開(kāi)發(fā)編輯器(IDE):我使用 社區(qū)版 IntelliJ,但是你也可以使用 Eclipse IDE 或者其他你喜歡的 Java IDE。
  • Git:如果你想克隆這個(gè)工程,你需要 Git 客戶(hù)端。

安裝好 Git 后運(yùn)行下列命令克隆這個(gè)工程:

  1. git clone https://github.com/bryantson/OpensourceDotComDemos.git

然后在你喜歡的 IDE 中,你可以將 TopDesignPatterns 倉(cāng)庫(kù)中的代碼作為 Apache Maven 項(xiàng)目導(dǎo)入。

我使用的是 Java,但你也可以使用支持抽象原則的任何編程語(yǔ)言來(lái)實(shí)現(xiàn)設(shè)計(jì)模式。

單例模式:避免每次創(chuàng)建一個(gè)對(duì)象

單例模式singleton pattern是非常流行的設(shè)計(jì)模式,它的實(shí)現(xiàn)相對(duì)來(lái)說(shuō)很簡(jiǎn)單,因?yàn)槟阒恍枰粋€(gè)類(lèi)。然而,許多開(kāi)發(fā)人員爭(zhēng)論單例設(shè)計(jì)模式的是否利大于弊,因?yàn)樗狈γ黠@的好處并且容易被濫用。很少有開(kāi)發(fā)人員直接實(shí)現(xiàn)單例;相反,像 Spring Framework 和 Google Guice 等編程框架內(nèi)置了單例設(shè)計(jì)模式的特性。

但是了解單例模式仍然有巨大的用處。單例模式確保一個(gè)類(lèi)僅創(chuàng)建一次且提供了一個(gè)對(duì)它的全局訪問(wèn)點(diǎn)。

單例模式:確保僅創(chuàng)建一個(gè)實(shí)例且避免在同一個(gè)項(xiàng)目中創(chuàng)建多個(gè)實(shí)例。

下面這幅圖展示了典型的類(lèi)對(duì)象創(chuàng)建過(guò)程。當(dāng)客戶(hù)端請(qǐng)求創(chuàng)建一個(gè)對(duì)象時(shí),構(gòu)造函數(shù)會(huì)創(chuàng)建或者實(shí)例化一個(gè)對(duì)象并調(diào)用方法返回這個(gè)類(lèi)給調(diào)用者。但是每次請(qǐng)求一個(gè)對(duì)象都會(huì)發(fā)生這樣的情況:構(gòu)造函數(shù)被調(diào)用,一個(gè)新的對(duì)象被創(chuàng)建并且它返回了一個(gè)獨(dú)一無(wú)二的對(duì)象。我猜面向?qū)ο笳Z(yǔ)言的創(chuàng)建者有每次都創(chuàng)建一個(gè)新對(duì)象的理由,但是單例過(guò)程的支持者說(shuō)這是冗余的且浪費(fèi)資源。

Normal class instantiation

Normal class instantiation

下面這幅圖使用單例模式創(chuàng)建對(duì)象。這里,構(gòu)造函數(shù)僅當(dāng)對(duì)象首次通過(guò)調(diào)用預(yù)先設(shè)計(jì)好的 getInstance() 方法時(shí)才會(huì)被調(diào)用。這通常通過(guò)檢查該值是否為 null 來(lái)完成,并且這個(gè)對(duì)象被作為私有變量保存在單例類(lèi)的內(nèi)部。下次 getInstance() 被調(diào)用時(shí),這個(gè)類(lèi)會(huì)返回第一次被創(chuàng)建的對(duì)象。而沒(méi)有新的對(duì)象產(chǎn)生;它只是返回舊的那一個(gè)。

Singleton pattern instantiation

Singleton pattern instantiation

下面這段代碼展示了創(chuàng)建單例模式最簡(jiǎn)單的方法:

  1. package org.opensource.demo.singleton;
  2.  
  3. public class OpensourceSingleton {
  4.  
  5.     private static OpensourceSingleton uniqueInstance;
  6.  
  7.     private OpensourceSingleton() {
  8.     }
  9.  
  10.     public static OpensourceSingleton getInstance() {
  11.         if (uniqueInstance == null) {
  12.             uniqueInstance = new OpensourceSingleton();
  13.         }
  14.         return uniqueInstance;
  15.     }
  16.  
  17. }

在調(diào)用方,這里展示了如何調(diào)用單例類(lèi)來(lái)獲取對(duì)象:

  1. Opensource newObject = Opensource.getInstance();

這段代碼很好的驗(yàn)證了單例模式的思想:

  1. 當(dāng) getInstance() 被調(diào)用時(shí),它通過(guò)檢查 null 值來(lái)檢查對(duì)象是否已經(jīng)被創(chuàng)建。
  2. 如果值為 null,它會(huì)創(chuàng)建一個(gè)新對(duì)象并把它保存到私有域,返回這個(gè)對(duì)象給調(diào)用者。否則直接返回之前被創(chuàng)建的對(duì)象。

單例模式實(shí)現(xiàn)的主要問(wèn)題是它忽略了并行進(jìn)程。當(dāng)多個(gè)進(jìn)程使用線程同時(shí)訪問(wèn)資源時(shí),這個(gè)問(wèn)題就產(chǎn)生了。對(duì)于這種情況有對(duì)應(yīng)的解決方案,它被稱(chēng)為雙重檢查鎖,用于多線程安全,如下所示:

  1. package org.opensource.demo.singleton;
  2.  
  3. public class ImprovedOpensourceSingleton {
  4.  
  5.     private volatile static ImprovedOpensourceSingleton uniqueInstance;
  6.  
  7.     private ImprovedOpensourceSingleton() {}
  8.  
  9.     public static ImprovedOpensourceSingleton getInstance() {
  10.         if (uniqueInstance == null) {
  11.             synchronized (ImprovedOpensourceSingleton.class) {
  12.                 if (uniqueInstance == null) {
  13.                     uniqueInstance = new ImprovedOpensourceSingleton();
  14.                 }
  15.             }
  16.         }
  17.         return uniqueInstance;
  18.     }
  19.  
  20. }

再?gòu)?qiáng)調(diào)一下前面的觀點(diǎn),確保只有在你認(rèn)為這是一個(gè)安全的選擇時(shí)才直接實(shí)現(xiàn)你的單例模式。最好的方法是通過(guò)使用一個(gè)制作精良的編程框架來(lái)利用單例功能。

工廠模式:將對(duì)象創(chuàng)建委派給工廠類(lèi)以隱藏創(chuàng)建邏輯

工廠模式factory pattern是另一種眾所周知的設(shè)計(jì)模式,但是有一小點(diǎn)復(fù)雜。實(shí)現(xiàn)工廠模式的方法有很多,而下列的代碼示例為最簡(jiǎn)單的實(shí)現(xiàn)方式。為了創(chuàng)建對(duì)象,工廠模式定義了一個(gè)接口,讓它的子類(lèi)去決定實(shí)例化哪一個(gè)類(lèi)。

工廠模式:將對(duì)象創(chuàng)建委派給工廠類(lèi),因此它能隱藏創(chuàng)建邏輯。

下列的圖片展示了最簡(jiǎn)單的工廠模式是如何實(shí)現(xiàn)的。

Factory pattern

Factory pattern

客戶(hù)端請(qǐng)求工廠類(lèi)創(chuàng)建類(lèi)型為 x 的某個(gè)對(duì)象,而不是客戶(hù)端直接調(diào)用對(duì)象創(chuàng)建。根據(jù)其類(lèi)型,工廠模式?jīng)Q定要?jiǎng)?chuàng)建和返回的對(duì)象。

在下列代碼示例中,OpensourceFactory 是工廠類(lèi)實(shí)現(xiàn),它從調(diào)用者那里獲取類(lèi)型并根據(jù)該輸入值決定要?jiǎng)?chuàng)建和返回的對(duì)象:

  1. package org.opensource.demo.factory;
  2.  
  3. public class OpensourceFactory {
  4.  
  5.     public OpensourceJVMServers getServerByVendor([String][18] name) {
  6.         if(name.equals("Apache")) {
  7.             return new Tomcat();
  8.         }
  9.         else if(name.equals("Eclipse")) {
  10.             return new Jetty();
  11.         }
  12.         else if (name.equals("RedHat")) {
  13.             return new WildFly();
  14.         }
  15.         else {
  16.             return null;
  17.         }
  18.     }
  19. }

OpenSourceJVMServer 是一個(gè) 100% 的抽象類(lèi)(即接口類(lèi)),它指示要實(shí)現(xiàn)的是什么,而不是怎樣實(shí)現(xiàn):

  1. package org.opensource.demo.factory;
  2.  
  3. public interface OpensourceJVMServers {
  4.     public void startServer();
  5.     public void stopServer();
  6.     public [String][18] getName();
  7. }

這是一個(gè) OpensourceJVMServers 類(lèi)的實(shí)現(xiàn)示例。當(dāng) RedHat 被作為類(lèi)型傳遞給工廠類(lèi),WildFly 服務(wù)器將被創(chuàng)建:

  1. package org.opensource.demo.factory;
  2.  
  3. public class WildFly implements OpensourceJVMServers {
  4.     public void startServer() {
  5.         [System][19].out.println("Starting WildFly Server...");
  6.     }
  7.  
  8.     public void stopServer() {
  9.         [System][19].out.println("Shutting Down WildFly Server...");
  10.     }
  11.  
  12.     public [String][18] getName() {
  13.         return "WildFly";
  14.     }
  15. }

觀察者模式:訂閱主題并獲取相關(guān)更新的通知

最后是觀察者模式observer pattern。像單例模式那樣,很少有專(zhuān)業(yè)的程序員直接實(shí)現(xiàn)觀察者模式。但是,許多消息隊(duì)列和數(shù)據(jù)服務(wù)實(shí)現(xiàn)都借用了觀察者模式的概念。觀察者模式在對(duì)象之間定義了一對(duì)多的依賴(lài)關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴(lài)它的對(duì)象都將被自動(dòng)地通知和更新。

觀察者模式:如果有更新,那么訂閱了該話題/主題的客戶(hù)端將被通知。

理解觀察者模式的最簡(jiǎn)單方法是想象一個(gè)郵件列表,你可以在其中訂閱任何主題,無(wú)論是開(kāi)源、技術(shù)、名人、烹飪還是您感興趣的任何其他內(nèi)容。每個(gè)主題維護(hù)者一個(gè)它的訂閱者列表,在觀察者模式中它們相當(dāng)于觀察者。當(dāng)某一個(gè)主題更新時(shí),它所有的訂閱者(觀察者)都將被通知這次改變。并且訂閱者總是能取消某一個(gè)主題的訂閱。

如下圖所示,客戶(hù)端可以訂閱不同的主題并添加觀察者以獲得最新信息的通知。因?yàn)橛^察者不斷的監(jiān)聽(tīng)著這個(gè)主題,這個(gè)觀察者會(huì)通知客戶(hù)端任何發(fā)生的改變。

Observer pattern

Observer pattern

讓我們來(lái)看看觀察者模式的代碼示例,從主題/話題類(lèi)開(kāi)始:

  1. package org.opensource.demo.observer;
  2.  
  3. public interface Topic {
  4.  
  5.     public void addObserver([Observer][22] observer);
  6.     public void deleteObserver([Observer][22] observer);
  7.     public void notifyObservers();
  8. }

這段代碼描述了一個(gè)為不同的主題去實(shí)現(xiàn)已定義方法的接口。注意一個(gè)觀察者如何被添加、移除和通知的。

這是一個(gè)主題的實(shí)現(xiàn)示例:

  1. package org.opensource.demo.observer;
  2.  
  3. import java.util.List;
  4. import java.util.ArrayList;
  5.  
  6. public class Conference implements Topic {
  7.     private List<Observer> listObservers;
  8.     private int totalAttendees;
  9.     private int totalSpeakers;
  10.     private [String][18] nameEvent;
  11.  
  12.     public Conference() {
  13.         listObservers = new ArrayList<Observer>();
  14.     }
  15.  
  16.     public void addObserver([Observer][22] observer) {
  17.         listObservers.add(observer);
  18.     }
  19.  
  20.     public void deleteObserver([Observer][22] observer) {
  21.         int i = listObservers.indexOf(observer);
  22.         if (i >= 0) {
  23.             listObservers.remove(i);
  24.         }
  25.     }
  26.  
  27.     public void notifyObservers() {
  28.         for (int i=0, nObservers = listObservers.size(); i < nObservers; ++ i) {
  29.             [Observer][22] observer = listObservers.get(i);
  30.             observer.update(totalAttendees,totalSpeakers,nameEvent);
  31.         }
  32.     }
  33.  
  34.     public void setConferenceDetails(int totalAttendees, int totalSpeakers, [String][18] nameEvent) {
  35.         this.totalAttendees = totalAttendees;
  36.         this.totalSpeakers = totalSpeakers;
  37.         this.nameEvent = nameEvent;
  38.         notifyObservers();
  39.     }
  40. }

這段代碼定義了一個(gè)特定主題的實(shí)現(xiàn)。當(dāng)發(fā)生改變時(shí),這個(gè)實(shí)現(xiàn)調(diào)用它自己的方法。注意這將獲取觀察者的數(shù)量,它以列表方式存儲(chǔ),并且可以通知和維護(hù)觀察者。

這是一個(gè)觀察者類(lèi):

  1. package org.opensource.demo.observer;
  2.  
  3. public interface [Observer][22] {
  4.     public void update(int totalAttendees, int totalSpeakers, [String][18] nameEvent);
  5. }

這個(gè)類(lèi)定義了一個(gè)接口,不同的觀察者可以實(shí)現(xiàn)該接口以執(zhí)行特定的操作。

例如,實(shí)現(xiàn)了該接口的觀察者可以在會(huì)議上打印出與會(huì)者和發(fā)言人的數(shù)量:

  1. package org.opensource.demo.observer;
  2.  
  3. public class MonitorConferenceAttendees implements [Observer][22] {
  4.     private int totalAttendees;
  5.     private int totalSpeakers;
  6.     private [String][18] nameEvent;
  7.     private Topic topic;
  8.  
  9.     public MonitorConferenceAttendees(Topic topic) {
  10.         this.topic = topic;
  11.         topic.addObserver(this);
  12.     }
  13.  
  14.     public void update(int totalAttendees, int totalSpeakers, [String][18] nameEvent) {
  15.         this.totalAttendees = totalAttendees;
  16.         this.totalSpeakers = totalSpeakers;
  17.         this.nameEvent = nameEvent;
  18.         printConferenceInfo();
  19.     }
  20.  
  21.     public void printConferenceInfo() {
  22.         [System][19].out.println(this.nameEvent + " has " + totalSpeakers + " speakers and " + totalAttendees + " attendees");
  23.     }
  24. }

接下來(lái)

現(xiàn)在你已經(jīng)閱讀了這篇對(duì)于設(shè)計(jì)模式的介紹引導(dǎo),你還可以去尋求了解其他設(shè)計(jì)模式,例如外觀模式,模版模式和裝飾器模式。也有一些并發(fā)和分布式系統(tǒng)的設(shè)計(jì)模式如斷路器模式和錨定模式。

可是,我相信最好的磨礪你的技能的方式首先是通過(guò)在你的業(yè)余項(xiàng)目或者練習(xí)中實(shí)現(xiàn)這些設(shè)計(jì)模式。你甚至可以開(kāi)始考慮如何在實(shí)際項(xiàng)目中應(yīng)用這些設(shè)計(jì)模式。接下來(lái),我強(qiáng)烈建議你查看 OOP 的 SOLID 原則。之后,你就準(zhǔn)備好了解其他設(shè)計(jì)模式。 

責(zé)任編輯:龐桂玉 來(lái)源: Linux中國(guó)
相關(guān)推薦

2011-07-14 14:46:46

設(shè)計(jì)模式

2010-08-11 09:15:07

設(shè)計(jì)模式Python

2023-10-19 13:43:00

設(shè)計(jì)模式軟件設(shè)計(jì)

2011-07-21 14:33:02

設(shè)計(jì)模式

2013-06-07 11:31:36

面向?qū)ο?/a>設(shè)計(jì)模式

2013-05-08 09:12:44

2022-09-19 06:25:14

設(shè)計(jì)模式GoF

2017-08-28 15:00:20

軟件系統(tǒng)架構(gòu)風(fēng)格

2022-02-16 07:32:10

性能代碼編程

2010-12-27 10:03:29

軟件設(shè)計(jì)師

2023-10-20 13:21:55

軟件設(shè)計(jì)模式架構(gòu)

2021-11-23 20:41:05

對(duì)象軟件設(shè)計(jì)

2012-12-25 09:38:41

JavaScript設(shè)計(jì)模式

2010-06-24 14:39:09

HART協(xié)議

2014-04-30 12:18:07

軟件設(shè)計(jì)

2012-04-12 09:38:21

JavaScript

2012-06-07 10:45:12

軟件架構(gòu)設(shè)計(jì)原則

2011-09-30 15:05:02

Android應(yīng)用十一

2010-06-28 15:23:43

SNMP協(xié)議

2012-05-09 12:35:48

美國(guó)YPiPad軟件
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)