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

繼承是代碼復(fù)用的最佳方案嗎?

開發(fā) 前端
代碼復(fù)用,很多人覺得繼承就是絕佳方案。若把繼承理解成代碼復(fù)用,更多是站在子類角度向上看。在客戶端代碼使用時(shí),面對(duì)的是子類,這種繼承叫實(shí)現(xiàn)繼承。

繼承,一個(gè)父類可有許多個(gè)子類。父類就是把一些公共代碼放進(jìn)去,之后在實(shí)現(xiàn)其他子類時(shí),少寫一些代碼。

代碼復(fù)用,很多人覺得繼承就是絕佳方案。若把繼承理解成代碼復(fù)用,更多是站在子類角度向上看。在客戶端代碼使用時(shí),面對(duì)的是子類,這種繼承叫實(shí)現(xiàn)繼承:

Child object = new Child();

還有一種看待繼承的角度:從父類往下看,客戶端使用時(shí),面對(duì)的是父類,這種繼承叫接口繼承:

Parent object = new Child();

但接口繼承更多和多態(tài)相關(guān)。本文主要討論實(shí)現(xiàn)繼承。

不推薦實(shí)現(xiàn)繼承:

? 繼承很寶貴,Java只支持單繼承 一個(gè)類只能有一個(gè)父類,一旦繼承的位置被實(shí)現(xiàn)繼承占據(jù),再想做接口繼承就難了

? 實(shí)現(xiàn)繼承通常也是一種受程序設(shè)計(jì)語(yǔ)言局限的思維方式 很多語(yǔ)言,不使用繼承,也有代碼復(fù)用方案

1、案例

產(chǎn)品報(bào)表服務(wù),其中的某服務(wù):查詢產(chǎn)品信息。該查詢過(guò)程通用,別的服務(wù)也可用。所以,我把它放父類以復(fù)用:

class BaseService {
// 獲取相應(yīng)產(chǎn)品信息
protected List<Product> getProducts(List<String> product) {
...
}
}

// 生成報(bào)表服務(wù)
class ReportService extends BaseService {
public void report() {
List<Product> product = getProduct(...);
// 生成報(bào)表
...
}
}

ReportService沒(méi)有繼承任何類,但也可復(fù)用代碼,即ProductFetcher模塊。這樣,若我需要有個(gè)獲取產(chǎn)品信息的地方,它不必非得是個(gè)服務(wù),我無(wú)需繼承任何類。

獲取產(chǎn)品信息、生成報(bào)表是兩件事,只是因?yàn)樵谏蓤?bào)表過(guò)程,需要獲取產(chǎn)品信息,所以,它有個(gè)基類。

不用繼承的實(shí)現(xiàn):

class ProductFetcher {
// 獲取相應(yīng)的產(chǎn)品信息
public List<Product> getProducts(List<String> product) {
...
}
}

// 生成報(bào)表服務(wù)
class ReportService {

private ProductFetcher fetcher;

public void report() {
List<Product> product = fetcher.getProducts(...);
// 生成報(bào)表
...
}
}

這就是組合:ReportService里組合一個(gè)ProductFetcher。設(shè)計(jì)通用原則:組合優(yōu)于繼承。即若一個(gè)方案既能用組合實(shí)現(xiàn),也能用繼承實(shí)現(xiàn),那就用組合。

所以,要寫繼承以實(shí)現(xiàn)代碼復(fù)用時(shí),問(wèn)問(wèn)自己,這是接口繼承,還是實(shí)現(xiàn)繼承?若是實(shí)現(xiàn)繼承,是不是可以寫成組合?

2、面向組合編程

可以組合的根因:獲取產(chǎn)品信息、生成報(bào)表服務(wù)本是兩件事(分離關(guān)注點(diǎn))。你要是看出是兩件事了,就不會(huì)把它們放一起。

分解是設(shè)計(jì)的第一步,分解粒度越小越好。當(dāng)可分解出多個(gè)關(guān)注點(diǎn),每個(gè)關(guān)注點(diǎn)就是個(gè)獨(dú)立類。最終類由這一個(gè)個(gè)小類組合而得,即面向組合編程。按面向組合思維:為增加復(fù)雜度,增加一個(gè)報(bào)表生成器(ReportGenerator),在獲取產(chǎn)品信息后,生成報(bào)表:

class ReportService {

private ProductFetcher fetcher;

private ReportGenerator generator;

public void report() {
List<Product> product = fetcher.getProducts(...);
// 生成報(bào)表
generator.generate(product);
}
}

OOP面向的是“對(duì)象”,不是類!很多程序員習(xí)慣把對(duì)象理解成類的附屬品,但在Alan Kay的理解中,對(duì)象本身就是獨(dú)立個(gè)體。所以,有些語(yǔ)言支持直接在對(duì)象操作。

現(xiàn)在,想給報(bào)表服務(wù)新增接口:處理產(chǎn)品信息。這樣的處理只會(huì)影響這里的一個(gè)對(duì)象,而同樣是這個(gè)ReportService的其他實(shí)例,則完全不受影響。

  • ? 好處 不必寫那么多類,根據(jù)需要,在程序運(yùn)行時(shí)組合出不同對(duì)象。

Java只有類這種組織方式,所以,很多有差異的概念只能用類這一個(gè)概念表示,思維受到限制,不同語(yǔ)言則提供不同的表現(xiàn)形式,讓概念更加清晰。

前面只是面向組合編程在思考方式的轉(zhuǎn)變,現(xiàn)在看設(shè)計(jì)差異。

3 案例

字體類(Font)需求:支持加粗、下劃線、斜體(Italic),且能任意組合。

3.1 繼承

需8個(gè)類:

圖片

3.2 組合

字體類(Font)只需三個(gè)獨(dú)立維度:是否加粗、下劃線、斜體。若再來(lái)一種需求,變成4種,采用繼承,類數(shù)量膨脹到16個(gè),而組合只需再增加一個(gè)維度。把一個(gè)M*N問(wèn)題,設(shè)計(jì)轉(zhuǎn)成M+N。

Java在面向組合編程方面能力較弱,但Java在嘗試不同方案。早期嘗試有Qi4j,后來(lái)Java 8加入default method,在一定程度上也可支持面向組合編程。

4、DCI

繼承是OOP原則之一,但編碼實(shí)踐中能用組合盡量使用組合。DCI也是一種編碼規(guī)范,對(duì)OOP的一種補(bǔ)充,核心思想也是關(guān)注點(diǎn)分離。

DCI是對(duì)象的Data數(shù)據(jù), 對(duì)象使用的Context場(chǎng)景, 對(duì)象的Interaction交互行為三者簡(jiǎn)稱, 是一種特別關(guān)注行為的模式(可對(duì)應(yīng)GoF行為模式),而MVC模式是一種結(jié)構(gòu)性模式,DCI可使用演員場(chǎng)景表演來(lái)解釋,某實(shí)體在某場(chǎng)景中扮演包公,實(shí)施包公升堂行為;典型事例是銀行帳戶轉(zhuǎn)帳,轉(zhuǎn)帳這行為按DDD很難劃分到帳號(hào)對(duì)象,它是跨兩個(gè)帳號(hào)實(shí)例之間的行為,可看成是帳號(hào)這個(gè)實(shí)體(PPT,見四色原型)在轉(zhuǎn)帳這個(gè)場(chǎng)景,實(shí)施了鈔票劃轉(zhuǎn)行為,這種新角度更貼近需求和自然,結(jié)合四色原型 DDD和DCI可以一步到位將需求更快地分解落實(shí)為可運(yùn)行的代碼,是國(guó)際上軟件領(lǐng)域的一場(chǎng)革命。摘自 https://www.jdon.com/dci.html

5、總結(jié)

組合優(yōu)于繼承。 復(fù)用方式背后的編程思想:面向組合編程。它給我們提供了一個(gè)不同的視角,但支撐面向組合編程的是分離關(guān)注點(diǎn)。將不同關(guān)注點(diǎn)分離,每個(gè)關(guān)注點(diǎn)成為一個(gè)模塊,在需要時(shí)組裝。面向組合編程,在設(shè)計(jì)本身上有很多優(yōu)秀地方,可降低程序復(fù)雜度,更是思維轉(zhuǎn)變。

參考

? https://www.infoq.cn/article/2007/11/qi4j-intro

? https://en.wikipedia.org/wiki/Data,_context_and_interaction

責(zé)任編輯:武曉燕 來(lái)源: JavaEdge
相關(guān)推薦

2022-07-01 16:02:36

開源安全

2012-03-07 09:02:29

代碼復(fù)用

2017-07-04 15:12:51

智慧城市PPP

2014-11-11 10:39:13

2013-03-14 09:33:14

遺留應(yīng)用公有云云計(jì)算

2023-11-02 12:48:00

游戲規(guī)則Flutter

2023-12-04 15:07:25

2016-02-23 09:09:55

2014-07-22 09:08:40

2023-08-26 20:51:25

Python函數(shù)代碼

2023-04-12 11:36:07

波分復(fù)用WDM

2022-10-27 15:08:16

物聯(lián)網(wǎng)智能建筑綠色建筑

2015-08-24 15:36:48

數(shù)據(jù)中心

2022-12-06 17:02:10

機(jī)器學(xué)習(xí)模型設(shè)置

2017-12-19 15:20:47

代碼應(yīng)用架構(gòu)

2024-11-01 15:33:04

2024-05-31 09:50:21

2012-09-18 10:48:47

服務(wù)器虛擬化Hypervisor虛擬化

2010-06-17 22:16:48

2012-08-09 09:10:56

代碼審查代碼
點(diǎn)贊
收藏

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