![18丨理論四接口隔離原則有哪三種應(yīng)用原則中的接口該如何理解_W_第1頁(yè)](http://file1.renrendoc.com/fileroot_temp2/2020-10/4/15076aad-fa45-452a-87b1-bec096775e0a/15076aad-fa45-452a-87b1-bec096775e0a1.gif)
![18丨理論四接口隔離原則有哪三種應(yīng)用原則中的接口該如何理解_W_第2頁(yè)](http://file1.renrendoc.com/fileroot_temp2/2020-10/4/15076aad-fa45-452a-87b1-bec096775e0a/15076aad-fa45-452a-87b1-bec096775e0a2.gif)
![18丨理論四接口隔離原則有哪三種應(yīng)用原則中的接口該如何理解_W_第3頁(yè)](http://file1.renrendoc.com/fileroot_temp2/2020-10/4/15076aad-fa45-452a-87b1-bec096775e0a/15076aad-fa45-452a-87b1-bec096775e0a3.gif)
![18丨理論四接口隔離原則有哪三種應(yīng)用原則中的接口該如何理解_W_第4頁(yè)](http://file1.renrendoc.com/fileroot_temp2/2020-10/4/15076aad-fa45-452a-87b1-bec096775e0a/15076aad-fa45-452a-87b1-bec096775e0a4.gif)
![18丨理論四接口隔離原則有哪三種應(yīng)用原則中的接口該如何理解_W_第5頁(yè)](http://file1.renrendoc.com/fileroot_temp2/2020-10/4/15076aad-fa45-452a-87b1-bec096775e0a/15076aad-fa45-452a-87b1-bec096775e0a5.gif)
版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、18 | 理論四:接口隔離原則有哪三種應(yīng)用?原則中的“接口”該如何理解?2019-12-13 王爭(zhēng)設(shè)計(jì)模式之美進(jìn)入課程講述:馮永吉時(shí)長(zhǎng) 13:56 大小 12.77M上幾節(jié)課中,我們學(xué)習(xí)了 SOLID 原則中的單一職責(zé)原則、開(kāi)閉原則和里式替換原則,今天我們學(xué)習(xí)第四個(gè)原則,接口隔離原則。它對(duì)應(yīng) SOLID 中的英文字母“I”。對(duì)于這個(gè)原則, 最關(guān)鍵就是理解其中“接口”的含義。那針對(duì)“接口”,不同的理解方式,對(duì)應(yīng)在原則上也有不同的解讀方式。除此之外,接口隔離原則跟我們之前講到的單一職責(zé)原則還有點(diǎn)兒類(lèi)似,所以今天我也會(huì)具體講一下它們之間的區(qū)別和聯(lián)系。話不多說(shuō),現(xiàn)在就讓我們正式開(kāi)始今天的學(xué)習(xí)吧!如何理
2、解“接口隔離原則”?加微信:642945106 發(fā)送“贈(zèng)送”領(lǐng)取贈(zèng)送精品課程發(fā)數(shù)字“2”獲取眾籌列表下載APP接口隔離原則的英文翻譯是“ Interface Segregation Principle”,縮寫(xiě)為 ISP。Robert Martin 在 SOLID 原則中是這樣定義它的:“Clients should not be forced to depend upon interfaces that they do not use。”直譯成中文的話就是:客戶端不應(yīng)該強(qiáng)迫依賴它不需要的接口。其中的“客戶端”,可以理解為接口的調(diào)用者或者使用者。實(shí)際上,“接口”這個(gè)名詞可以用在很多場(chǎng)合中。生活中
3、我們可以用它來(lái)指插座接口等。在軟件開(kāi)發(fā)中,我們既可以把它看作一組抽象的約定,也可以具體指系統(tǒng)與系統(tǒng)之間的 API接口,還可以特指面向?qū)ο缶幊陶Z(yǔ)言中的接口等。前面我提到,理解接口隔離原則的關(guān)鍵,就是理解其中的“接口”二字。在這條原則中,我們可以把“接口”理解為下面三種東西:一組 API 接口集合單個(gè) API 接口或函數(shù)OOP 中的接口概念接下來(lái),我就按照這三種理解方式來(lái)詳細(xì)講一下,在不同的場(chǎng)景下,這條原則具體是如何解讀和應(yīng)用的。把“接口”理解為一組 API 接口集合我們還是結(jié)合一個(gè)例子來(lái)講解。微服務(wù)用戶系統(tǒng)提供了一組跟用戶相關(guān)的 API 給其他系統(tǒng)使用,比如:注冊(cè)、登錄、獲取用戶信息等。具體代碼
4、如下所示:復(fù)制代碼12345678910public interface UserService boolean register(String cellphone, String password); boolean login(String cellphone, String password); UserInfo getUserInfoById(long id);UserInfo getUserInfoByCellphone(String cellphone);public class UserServiceImpl implements UserService /.現(xiàn)在,我們的管理系統(tǒng)
5、要實(shí)現(xiàn)刪除用戶的功能,希望用戶系統(tǒng)提供一個(gè)刪除用戶的接口。這個(gè)時(shí)候我們?cè)撊绾蝸?lái)做呢?你可能會(huì)說(shuō),這不是很簡(jiǎn)單嗎,我只需要在 UserService中新添加一個(gè) deleteUserByCellphone() 或 deleteUserById() 接口就可以了。這個(gè)方法可以解決問(wèn)題,但是也隱藏了一些安全隱患。刪除用戶是一個(gè)非常慎重的操作,我們只希望通過(guò)管理系統(tǒng)來(lái)執(zhí)行,所以這個(gè)接口只限于給管理系統(tǒng)使用。如果我們把它放到 UserService 中,那所有使用到 UserService的系統(tǒng),都可以調(diào)用這個(gè)接口。不加限制地被其他業(yè)務(wù)系統(tǒng)調(diào)用,就有可能導(dǎo)致誤刪用戶。當(dāng)然,最好的解決方案是從架構(gòu)設(shè)計(jì)的層
6、面,通過(guò)接口鑒權(quán)的方式來(lái)限制接口的調(diào)用。不過(guò),如果暫時(shí)沒(méi)有鑒權(quán)框架來(lái)支持,我們還可以從代碼設(shè)計(jì)的層面,盡量避免接口被誤用。我們參照接口隔離原則,調(diào)用者不應(yīng)該強(qiáng)迫依賴它不需要的接口,將刪除接口單獨(dú)放到另外一個(gè)接口 RestrictedUserService 中,然后將 RestrictedUserService 只打包提供給理系統(tǒng)來(lái)使用。具體的代碼實(shí)現(xiàn)如下所示:管復(fù)制代碼123456789101112131415public interface UserService boolean register(String cellphone, String password); boolean log
7、in(String cellphone, String password); UserInfo getUserInfoById(long id);UserInfo getUserInfoByCellphone(String cellphone);public interface RestrictedUserService boolean deleteUserByCellphone(String cellphone); boolean deleteUserById(long id);public class UserServiceImpl implements UserService, Rest
8、rictedUserService / . 省略實(shí)現(xiàn)代碼.在剛剛的這個(gè)例子中,我們把接口隔離原則中的接口,理解為一組接口集合,它可以是某個(gè)微服務(wù)的接口,也可以是某個(gè)類(lèi)庫(kù)的接口等等。在設(shè)計(jì)微服務(wù)或者類(lèi)庫(kù)接口的時(shí)候,如果部 分接口只被部分調(diào)用者使用,那我們就需要將這部分接口隔離出來(lái),單獨(dú)給對(duì)應(yīng)的調(diào)用者使 用,而不是強(qiáng)迫其他調(diào)用者也依賴這部分不會(huì)被用到的接口。把“接口”理解為單個(gè) API 接口或函數(shù)現(xiàn)在我們?cè)贀Q一種理解方式,把接口理解為單個(gè)接口或函數(shù)(以下為了方便講解,我都簡(jiǎn)稱(chēng)為“函數(shù)”)。那接口隔離原則就可以理解為:函數(shù)的設(shè)計(jì)要功能單一,不要將多個(gè)不同的功能邏輯在一個(gè)函數(shù)中實(shí)現(xiàn)。接下來(lái),我們還是通
9、過(guò)一個(gè)例子來(lái)解釋一下。在上面的代碼中,count() 函數(shù)的功能不夠單一,包含很多不同的統(tǒng)計(jì)功能,比如,求最大值、最小值、平均值等等。按照接口隔離原則,我們應(yīng)該把 count() 函數(shù)拆成幾個(gè)更小粒度的函數(shù),每個(gè)函數(shù)負(fù)責(zé)一個(gè)獨(dú)立的統(tǒng)計(jì)功能。拆分之后的代碼如下所示:不過(guò),你可能會(huì)說(shuō),在某種意義上講,count() 函數(shù)也不能算是職責(zé)不夠單一,畢竟它做的事情只跟統(tǒng)計(jì)相關(guān)。我們?cè)谥v單一職責(zé)原則的時(shí)候,也提到過(guò)類(lèi)似的問(wèn)題。實(shí)際上,判定功能是否單一,除了很強(qiáng)的主觀性,還需要結(jié)合具體的場(chǎng)景。如果在項(xiàng)目中,對(duì)每個(gè)統(tǒng)計(jì)需求,Statistics 定義的那幾個(gè)統(tǒng)計(jì)信息都有涉及,那 count() 函數(shù)的設(shè)計(jì)就是
10、合理的。相反,如果每個(gè)統(tǒng)計(jì)需求只涉及 Statistics 羅列的統(tǒng)計(jì)信息中一部分,比如,有的只需要用到 max、min、average 這三類(lèi)統(tǒng)計(jì)信息,有的只需要用到average、sum。而 count() 函數(shù)每次都會(huì)把所有的統(tǒng)計(jì)信息計(jì)算一遍,就會(huì)做很多無(wú)用復(fù)制代碼1 public Long max(Collection dataSet) /. 2 public Long min(Collection dataSet) /. 3 public Long average(Colletion dataSet) /. 4 / . 省略其他統(tǒng)計(jì)函數(shù).復(fù)制代碼1 public class Stat
11、istics 2 private Long max;3 private Long min;4 private Long average;5 private Long sum;6 private Long percentile99;7 private Long percentile999;8 /. 省略 constructor/getter/setter 等方法.9 1011 public Statistics count(Collection dataSet) 12 Statistics statistics = new Statistics();13/. 省略計(jì)算邏輯.14return st
12、atistics;15 功,勢(shì)必影響代碼的性能,特別是在需要統(tǒng)計(jì)的數(shù)據(jù)量很大的時(shí)候。所以,在這個(gè)應(yīng)用場(chǎng)景下,count()函數(shù)的設(shè)計(jì)就有點(diǎn)不合理了,我們應(yīng)該按照第二種設(shè)計(jì)思路,將其拆分成粒度更細(xì)的多個(gè)統(tǒng)計(jì)函數(shù)。不過(guò),你應(yīng)該已經(jīng)發(fā)現(xiàn),接口隔離原則跟單一職責(zé)原則有點(diǎn)類(lèi)似,不過(guò)稍微還是有點(diǎn)區(qū)別。單一職責(zé)原則針對(duì)的是模塊、類(lèi)、接口的設(shè)計(jì)。而接口隔離原則相對(duì)于單一職責(zé)原則,一方面它更側(cè)重于接口的設(shè)計(jì),另一方面它的思考的角度不同。它提供了一種判斷接口是否職責(zé)單一的標(biāo)準(zhǔn):通過(guò)調(diào)用者如何使用接口來(lái)間接地判定。如果調(diào)用者只使用部分接口或接口的部分功能,那接口的設(shè)計(jì)就不夠職責(zé)單一。把“接口”理解為 OOP 中的接
13、口概念除了剛講過(guò)的兩種理解方式,我們還可以把“接口”理解為 OOP 中的接口概念,比如Java 中的 interface。我還是通過(guò)一個(gè)例子來(lái)給你解釋。假設(shè)我們的項(xiàng)目中用到了三個(gè)外部系統(tǒng):Redis、MySQL、Kafka。每個(gè)系統(tǒng)都對(duì)應(yīng)一系列配置信息,比如地址、端口、訪問(wèn)超時(shí)時(shí)間等。為了在內(nèi)存中存儲(chǔ)這些配置信息,供項(xiàng)目中的其他模塊來(lái)使用,我們分別設(shè)計(jì)實(shí)現(xiàn)了三個(gè) Configuration 類(lèi):RedisConfig、MysqlConfig、KafkaConfig。具體的代碼實(shí)現(xiàn)如下所示。注意,這里我只給出了RedisConfig 的代碼實(shí)現(xiàn),另外兩個(gè)都是類(lèi)似的,我這里就不貼了。復(fù)制代碼123
14、45678910111213141516171819public class RedisConfig ConfigSource configSource; / 配置中心(比如 zookeeper)String address; int timeout;int maxTotal;private private privateprivate/ 省略其他配置: maxWaitMillis,maxIdle,minIdle.public RedisConfig(ConfigSource configSource) this.configSource = configSource;public Strin
15、g getAddress() return this.address;/. 省略其他 get()、init() 方法.public void update() / 從 configSource 加載配置到 address/timeout/maxTotal.202122 public class KafkaConfig /. 省略. public class MysqlConfig /. 省略. 23現(xiàn)在,我們有一個(gè)新的功能需求,希望支持 Redis 和 Kafka 配置信息的熱更新。所謂“熱更新(hot update)”就是,如果在配置中心中更改了配置信息,我們希望在不用重啟系統(tǒng)的情況下,能將
16、最新的配置信息加載到內(nèi)存中(也就是 RedisConfig、KafkaConfig 類(lèi)中)。但是,因?yàn)槟承┰颍覀儾⒉幌M麑?duì) MySQL 的配置信息進(jìn)行熱更新。為了實(shí)現(xiàn)這樣一個(gè)功能需求,我們?cè)O(shè)計(jì)實(shí)現(xiàn)了一個(gè) ScheduledUpdater 類(lèi),以固定時(shí)間頻率(periodInSeconds)來(lái)調(diào)用 RedisConfig、KafkaConfig 的 update() 方法更新配置信息。具體的代碼實(shí)現(xiàn)如下所示:復(fù)制代碼123456789101112131415161718192021222324252627282930publicvoidinterface Updater update();p
17、ublicclass RedisConfig implemets Updater /. 省略其他屬性和方法.Overridepublic void update() /. public class KafkaConfig implements Updater /. 省略其他屬性和方法. Overridepublic void update() /. public class MysqlConfig /. 省略其他屬性和方法.public class ScheduledUpdater private private privateprivatefinal ScheduledExecutorSer
18、vice executor long initialDelayInSeconds;long periodInSeconds;Updater updater;= Executors.newSingleThreapublic ScheduleUpdater(Updater updater, long initialDelayInSeconds, long p this.updater = updater;this.initialDelayInSeconds = initialDelayInSeconds; this.periodInSeconds = periodInSeconds;3132333
19、43536373839404142434445464748495051525354public void run() executor.scheduleAtFixedRate(new Runnable() Overridepublic void run() updater.update();, this.initialDelayInSeconds, this.periodInSeconds, TimeUnit.SECONDS)public class Application ConfigSource configSource = newZookeeperConfigSource(/* 省略參數(shù)
20、 */);public publicpublicstatic staticstaticfinal finalfinalRedisConfig KafkaConfigMySqlConfigredisConfig kafkaConfigmysqlConfig=new newnewRedisConfig(configSource); KakfaConfig(configSource);MysqlConfig(configSource);publicstaticvoid main(String args) ScheduledUpdater redisConfigUpdater = newredisCo
21、nfigUpdater.run();ScheduledUpdater(redisConfig, 30ScheduledUpdater kafkaConfigUpdater = newredisConfigUpdater.run();ScheduledUpdater(kafkaConfig, 60剛剛的熱更新的需求我們已經(jīng)搞定了?,F(xiàn)在,我們又有了一個(gè)新的監(jiān)控功能需求。通過(guò)命令行來(lái)查看 Zookeeper 中的配置信息是比較麻煩的。所以,我們希望能有一種更加方便的配置信息查看方式。我們可以在項(xiàng)目中開(kāi)發(fā)一個(gè)內(nèi)嵌的SimpleHttpServer,輸出項(xiàng)目的配置信息到一個(gè)固定的HTTP 地址,比如:h
22、ttp:/:2389/config 。我們只需要在瀏覽器中輸入這個(gè)地址,就可以顯示出系統(tǒng)的配置信息。不過(guò),出于某些原因,我們只想暴露 MySQL 和 Redis的配置信息,不想暴露 Kafka 的配置信息。為了實(shí)現(xiàn)這樣一個(gè)功能,我們還需要對(duì)上面的代碼做進(jìn)一步改造。改造之后的代碼如下所示:復(fù)制代碼12345publicvoidinterface Updater update();publicinterface Viewer 678910111213141516171819202122232425262728293031323334353637383940414243444546
23、4748495051525354555657String outputInPlainText();Map output();public class RedisConfig implemets Updater, Viewer/. 省略其他屬性和方法. Overridepublic void update() /. Overridepublic String outputInPlainText() /. Overridepublic Map output() /.Updater public class KafkaConfig implements/. 省略其他屬性和方法. Overridepu
24、blic void update() /. public class MysqlConfig implements/. 省略其他屬性和方法. Overridepublic String outputInPlainText()OverrideViewer /. public Map output() /.public class SimpleHttpServer private privateprivateString host; int port;MapString, List viewers = new HashMap();public SimpleHttpServer(String hos
25、t, int port) /.public void addViewers(String urlDirectory, Viewer viewer) if (!viewers.containsKey(urlDirectory) viewers.put(urlDirectory, new ArrayList();this.viewers.get(urlDirectory).add(viewer);public void run() /. public class Application ConfigSource configSource = newZookeeperConfigSource();p
26、ublic publicpublicstatic staticstaticfinal finalfinalRedisConfig KafkaConfigMySqlConfigredisConfig kafkaConfigmysqlConfig=new newnewRedisConfig(configSource KakfaConfig(configSourceMySqlConfig(configSourcepublicstaticvoid main(String args) 5859606162636465666768697071ScheduledUpdater redisConfigUpda
27、ter =new ScheduledUpdater(redisConfig, 300, 300); redisConfigUpdater.run();ScheduledUpdater kafkaConfigUpdater =new ScheduledUpdater(kafkaConfig, 60, 60); redisConfigUpdater.run();SimpleHttpServer simpleHttpServer = new SimpleHttpServer(“”, simpleHttpServer.addViewer(/config, redisConfig);
28、simpleHttpServer.addViewer(/config, mysqlConfig);simpleHttpServer.run();至此,熱更新和監(jiān)控的需求我們就都實(shí)現(xiàn)了。我們來(lái)回顧一下這個(gè)例子的設(shè)計(jì)思想。我們?cè)O(shè)計(jì)了兩個(gè)功能非常單一的接口:Updater 和 Viewer。ScheduledUpdater 只依賴Updater 這個(gè)跟熱更新相關(guān)的接口,不需要被強(qiáng)迫去依賴不需要的 Viewer 接口,滿足接口隔離原則。同理,SimpleHttpServer 只依賴跟查看信息相關(guān)的 Viewer 接口,不依賴不需要的 Updater 接口,也滿足接口隔離原則。你可能會(huì)說(shuō),如果我們不遵守
29、接口隔離原則,不設(shè)計(jì) Updater 和 Viewer 兩個(gè)小接口,而是設(shè)計(jì)一個(gè)大而全的 Config 接口,讓 RedisConfig、KafkaConfig、MysqlConfig 都實(shí)現(xiàn)這個(gè) Config 接口,并且將原來(lái)傳遞給 ScheduledUpdater 的 Updater 和傳遞給SimpleHttpServer 的 Viewer,都替換為 Config,那會(huì)有什么問(wèn)題呢?我們先來(lái)看一下, 按照這個(gè)思路來(lái)實(shí)現(xiàn)的代碼是什么樣的。復(fù)制代碼1234567891011121314public interface Config void update();String outputInP
30、lainText(); Map output();public class RedisConfig implements Config /. 需要實(shí)現(xiàn) Config 的三個(gè)接口 update/outputIn./outputpublic class KafkaConfig implements Config /. 需要實(shí)現(xiàn) Config 的三個(gè)接口 update/outputIn./output15161718192021222324252627282930313233343536373839404142434445public class MysqlConfig implements Con
31、fig /. 需要實(shí)現(xiàn) Config 的三個(gè)接口 update/outputIn./outputpublic class ScheduledUpdater /. 省略其他屬性和方法. private Config config;public ScheduleUpdater(Config config, long initialDelayInSeconds, this.config = config;/./.longperiopublic class SimpleHttpServer private privateprivateString host; int port;MapString, L
32、ist viewers = new HashMap();public SimpleHttpServer(String host, int port) /.public void addViewer(String urlDirectory, Config config) if (!viewers.containsKey(urlDirectory) viewers.put(urlDirectory, new ArrayList();viewers.get(urlDirectory).add(config);public void run() /. 這樣的設(shè)計(jì)思路也是能工作的,但是對(duì)比前后兩個(gè)設(shè)計(jì)思
33、路,在同樣的代碼量、實(shí)現(xiàn)復(fù)雜度、同等可讀性的情況下,第一種設(shè)計(jì)思路顯然要比第二種好很多。為什么這么說(shuō)呢?主要有兩點(diǎn)原因。首先,第一種設(shè)計(jì)思路更加靈活、易擴(kuò)展、易復(fù)用。因?yàn)?Updater、Viewer 職責(zé)更加單一,單一就意味了通用、復(fù)用性好。比如,我們現(xiàn)在又有一個(gè)新的需求,開(kāi)發(fā)一個(gè) Metrics 性能統(tǒng)計(jì)模塊,并且希望將 Metrics 也通過(guò) SimpleHttpServer 顯示在網(wǎng)頁(yè)上,以方便查看。這個(gè)時(shí)候,盡管 Metrics 跟 RedisConfig 等沒(méi)有任何關(guān)系,但我們?nèi)匀豢梢宰孧etrics 類(lèi)實(shí)現(xiàn)非常通用的 Viewer 接口,復(fù)用 SimpleHttpServer 的
34、代碼實(shí)現(xiàn)。具體的代碼如下所示:復(fù)制代碼1234567891011121314151617181920publicpublicclassclassApiMetrics implements Viewer /.DbMetrics implements Viewer /.publicclassApplication ConfigSource configSource = newZookeeperConfigSource();public public public publicpublicstatic static static staticstaticfinal final final final
35、finalRedisConfig KafkaConfigMySqlConfigredisConfig kafkaConfigmySqlConfig=new newnewRedisConfig(configSource KakfaConfig(configSourceMySqlConfig(configSourceApiMetrics apiMetrics =new ApiMetrics();DbMetrics dbMetrics = new DbMetrics();publicstaticvoid main(String args) SimpleHttpServer simpleHttpSer
36、ver = new SimpleHttpServer(“”, simpleHttpServer.addViewer(/config, redisConfig); simpleHttpServer.addViewer(/config, mySqlConfig); simpleHttpServer.addViewer(/metrics, apiMetrics); simpleHttpServer.addViewer(/metrics, dbMetrics);simpleHttpServer.run();其次,第二種設(shè)計(jì)思路在代碼實(shí)現(xiàn)上做了一些無(wú)用功。因?yàn)?Config 接口中包含
37、兩類(lèi)不相關(guān)的 接 口 , 一 類(lèi) 是 update(), 一 類(lèi) 是 output() 和 outputInPlainText() 。 理 論 上 , KafkaConfig 只需要實(shí)現(xiàn) update() 接口,并不需要實(shí)現(xiàn) output() 相關(guān)的接口。同理, MysqlConfig 只需要實(shí)現(xiàn) output() 相關(guān)接口,并需要實(shí)現(xiàn) update() 接口。但第二種設(shè)計(jì)思路要求 RedisConfig、KafkaConfig、MySqlConfig 必須同時(shí)實(shí)現(xiàn) Config 的所有接口函數(shù)(update、output、outputInPlainText)。除此之外,如果我們要往 Conf
38、ig 中繼續(xù)添加一個(gè)新的接口,那所有的實(shí)現(xiàn)類(lèi)都要改動(dòng)。相反,如果我們的接口粒度比較小,那涉及改動(dòng)的類(lèi)就比較少。重點(diǎn)回顧今天的內(nèi)容到此就講完了。我們一塊來(lái)總結(jié)回顧一下,你需要掌握的重點(diǎn)內(nèi)容。1. 如何理解“接口隔離原則”?理解“接口隔離原則”的重點(diǎn)是理解其中的“接口”二字。這里有三種不同的理解。如果把“接口”理解為一組接口集合,可以是某個(gè)微服務(wù)的接口,也可以是某個(gè)類(lèi)庫(kù)的接口等。如果部分接口只被部分調(diào)用者使用,我們就需要將這部分接口隔離出來(lái),單獨(dú)給這部分調(diào)用者使用,而不強(qiáng)迫其他調(diào)用者也依賴這部分不會(huì)被用到的接口。如果把“接口”理解為單個(gè) API 接口或函數(shù),部分調(diào)用者只需要函數(shù)中的部分功能,那我們
39、就需要把函數(shù)拆分成粒度更細(xì)的多個(gè)函數(shù),讓調(diào)用者只依賴它需要的那個(gè)細(xì)粒度函數(shù)。如果把“接口”理解為 OOP 中的接口,也可以理解為面向?qū)ο缶幊陶Z(yǔ)言中的接口語(yǔ)法。那接口的設(shè)計(jì)要盡量單一,不要讓接口的實(shí)現(xiàn)類(lèi)和調(diào)用者,依賴不需要的接口函數(shù)。2. 接口隔離原則與單一職責(zé)原則的區(qū)別單一職責(zé)原則針對(duì)的是模塊、類(lèi)、接口的設(shè)計(jì)。接口隔離原則相對(duì)于單一職責(zé)原則,一方面更側(cè)重于接口的設(shè)計(jì),另一方面它的思考角度也是不同的。接口隔離原則提供了一種判斷接 口的職責(zé)是否單一的標(biāo)準(zhǔn):通過(guò)調(diào)用者如何使用接口來(lái)間接地判定。如果調(diào)用者只使用部分 接口或接口的部分功能,那接口的設(shè)計(jì)就不夠職責(zé)單一。課堂討論今天課堂討論的話題是這樣的:
40、java.util.concurrent 并發(fā)包提供了 AtomicInteger 這樣一個(gè)原子類(lèi),其中有一個(gè)函數(shù)getAndIncrement() 是這樣定義的:給整數(shù)增加一,并且返回未増之前的值。我的問(wèn)題是,這個(gè)函數(shù)的設(shè)計(jì)是否符合單一職責(zé)原則和接口隔離原則?為什么?歡迎在留言區(qū)寫(xiě)下你的答案,和同學(xué)一起交流和分享。如果有收獲,也歡迎你把這篇文章分享給你的朋友。復(fù)制代碼1 /*2 * Atomically increments by one the current value.3 * return the previous value4*/5 public final int getAndIn
41、crement() /. 版權(quán)歸極客邦科技所有,未經(jīng)許可不得傳播售賣(mài)。 頁(yè)面已增加防盜追蹤,如有侵權(quán)極客邦將依法追究其法律責(zé)任。上一篇17 | 理論三:里式替換(LSP)跟多態(tài)有何區(qū)別?哪些代碼違背了LSP?下一篇19 | 理論五:控制反轉(zhuǎn)、依賴反轉(zhuǎn)、依賴注入,這三者有何區(qū)別和聯(lián)系?精選留言 (61)辣么大2019-12-13Java.util.concurrent.atomic包下提供了機(jī)器底層級(jí)別實(shí)現(xiàn)的多線程環(huán)境下原子操作,相比自己實(shí)現(xiàn)類(lèi)似的功能更加高效。AtomicInteger提供了intValue() 獲取當(dāng)前值incrementAndGet() 相當(dāng)于+i展開(kāi)寫(xiě)留言431NoAsk
42、2019-12-13單一職責(zé)原則針對(duì)的是模塊、類(lèi)、接口的設(shè)計(jì)。getAndIncrease()雖然集合了獲取和增加兩個(gè)功能,但是它作為對(duì)atomicInteger的值的常用方法,提供對(duì)其值的常規(guī)操作,是滿足單一原則的。從單一原則的下面這個(gè)解釋考慮,是不滿足接口隔離原則的。“如果調(diào)用者只使用部分展開(kāi)111時(shí)光流逝,而我們?cè)诟?2019-12-13老師可以每次課對(duì)上一次課的思考題做下解答嗎展開(kāi)作者回復(fù): 集中答疑一下吧 課都提前錄好了10李小四2019-12-13設(shè)計(jì)模式_18純理論分析,這么設(shè)計(jì)是不符合“接口隔離”原則的,畢竟,get是一個(gè)操作,increment 是另一個(gè)操作。結(jié)合具體場(chǎng)景,A
43、tomic類(lèi)的設(shè)計(jì)目的是保證操作的原子性,專(zhuān)門(mén)看了一下AtomicIntege展開(kāi)26北島明月2019-12-13理由是這個(gè)方法完成的邏輯就是一個(gè)功能:新增和返回舊值。只不過(guò)是兩步操作罷了。如果你想獲取,就用get方法,自增就用increment 方法。都有提供哇。展開(kāi)5小晏子2019-12-13思考題:先看是否符合單一職責(zé)原則,這個(gè)函數(shù)的功能是加1然后返回之前的值,做了兩件事,是不符合單一職責(zé)原則的!但是卻符合接口隔離原則,從調(diào)用者的角度來(lái)看的話,因?yàn)檫@個(gè)類(lèi)是Atomic類(lèi),需要的所有操作都是原子的,所以為了滿足調(diào)用者需要原子性的完成加一返回的操作,提供一個(gè)展開(kāi)4墨雨2019-12-13單一
44、職責(zé)是針對(duì)于模塊、類(lèi)在具體的需求業(yè)務(wù)場(chǎng)景下是否符合只做一件事情的原則。而接口隔離原則就細(xì)化到了接口方面,我是這樣理解的,如果接口中的某些方法對(duì)于需要繼承實(shí)現(xiàn)它的類(lèi)來(lái)說(shuō)是多余的,那么這個(gè)接口的設(shè)計(jì)就不符合接口隔離原則,可以考慮再拆分細(xì)化。對(duì)于課后思考題,他只對(duì)該數(shù)做了相關(guān)操作符合單一職責(zé)原則。但從接口、函數(shù)來(lái)看它展開(kāi)13黃林晴2019-12-13思考題:個(gè)人感覺(jué),不符合單一職責(zé),也不符合接口隔離,因?yàn)楹瘮?shù)做了兩件事,不應(yīng)該把獲取當(dāng)前值和值加1放在一起,因?yàn)?.用戶可能需要-1 *1等其他運(yùn)算操作再返回原始值,這樣就要n個(gè)方法每個(gè)方法中都有返回原始值的操作。展開(kāi)2Chen2019-12-13getAndIncrement()符合接口隔離原則,這是不是一個(gè)大而全的函數(shù),而是一個(gè)細(xì)粒度的函數(shù),跟
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025公對(duì)私房屋租賃合同
- 2025個(gè)人機(jī)械加工合同
- 保密專(zhuān)項(xiàng)培訓(xùn)合同范本
- 公司配送合同范例
- 個(gè)人訂單合同范例
- 勞務(wù)合同范本買(mǎi)工傷
- 會(huì)展購(gòu)銷(xiāo)合同范例
- 公司車(chē)間廢品收購(gòu)合同范例
- 中介合同建材買(mǎi)賣(mài)合同范例
- 21新版合同范例
- 2023年北京自然博物館招考聘用筆試參考題庫(kù)附答案詳解
- 密度計(jì)法顆粒分析試驗(yàn)記錄(自動(dòng)和計(jì)算)
- 土方轉(zhuǎn)運(yùn)方案
- (11.3.1)-10.3蒸汽壓縮制冷循環(huán)
- JJF(紡織)064-2013織物防鉆絨性試驗(yàn)儀(摩擦法)校準(zhǔn)規(guī)范
- GB/T 21797-2008化學(xué)品有機(jī)磷化合物28天重復(fù)劑量的遲發(fā)性神經(jīng)毒性試驗(yàn)
- 2023年湖北成人學(xué)位英語(yǔ)考試真題
- 園區(qū)保安巡邏崗標(biāo)準(zhǔn)作業(yè)規(guī)程
- SJG 112-2022 既有建筑幕墻安全性鑒定技術(shù)標(biāo)準(zhǔn)高清最新版
- 旅游文本的翻譯課件
- 最全新能源材料-鋰離子電池材料189張課件
評(píng)論
0/150
提交評(píng)論