1 回答

TA貢獻(xiàn)1884條經(jīng)驗(yàn) 獲得超4個(gè)贊
這是我用來(lái)談?wù)撛撝黝}的上下文。設(shè)函數(shù) f 有以下選項(xiàng):
interface Y { ... }
class SubY implements Y { ... }
DEFINITION CHOICE:
public SubY f() { ... }
OR
public Y f() { ... }
USAGE CHOICE:
...
Y y = f();
OR
SubY y = f(); //maybe with a cast
...
SubY從技術(shù)上講,所有選項(xiàng)都可以是正確的,具體取決于您是否打算向最終用戶(下一個(gè)程序員) 公開詳細(xì)信息。SubY如果向最終用戶公開看起來(lái)是個(gè)壞主意,那就不要這樣做。否則,就這樣做。推理如下:從概念上講,您應(yīng)該始終返回可能需要的最窄類型(較窄的類型位于類層次結(jié)構(gòu)
的更下方- 將其視為“較窄的類型是較寬的類型”)。例如,如果您返回 a ,則意味著您希望最終用戶僅通過(guò)界面與其進(jìn)行交互。但是,如果您預(yù)計(jì)最終用戶將需要 中定義的交互,請(qǐng)返回該交互。 一般來(lái)說(shuō),這個(gè)想法是使方法的返回類型盡可能窄,而不暴露最終用戶不應(yīng)該知道的血腥細(xì)節(jié)。只要您正確隱藏類處理的內(nèi)部細(xì)節(jié),返回. 另一方面,考慮最終用戶的責(zé)任: 最終用戶的責(zé)任是負(fù)責(zé)任地使用狹窄的返回類型賦予他們的權(quán)力。您已經(jīng)通過(guò)正確隱藏內(nèi)部結(jié)構(gòu)來(lái)阻止他們做出令人討厭的事情。然后,當(dāng)最終用戶使用您的類時(shí),他們應(yīng)該根據(jù)自己的需求進(jìn)行編程,如下所示:ListArrayList
SubYSubY
// imported library provides:
public SubY f() { ... }
... // la la la
Y y = f();
useYFunctionality(y);
... // somewhere else that you need SubY functionality
SubY subY = f();
useSubYFunctionality(subY);
因此,程序員應(yīng)該定義他們的函數(shù)來(lái)返回精確的類型,返回盡可能窄的安全實(shí)現(xiàn)(可以是一個(gè)接口)。另一方面,該服務(wù)/功能的最終用戶應(yīng)該將其變量定義為仍然有效的最廣泛的可能類型,以減少耦合并提高意圖的清晰度(如果這是您所需要的,請(qǐng)使用而getLicensePlateNumber不是Vehicle)VeryUnreliableCar。這里的關(guān)鍵是選擇返回類型沒有明確的答案。相反,請(qǐng)根據(jù)您的判斷來(lái)決定哪些內(nèi)容應(yīng)該暴露給最終用戶,哪些內(nèi)容不應(yīng)該暴露給最終用戶。如果沒有特殊原因拒絕訪問(wèn)SubY,請(qǐng)記住以下原則:Functions Return Accurately, Users Define Variables As Necessary或 FRAUDVAN。
將其應(yīng)用到您的示例中:
class SubY_generalist implements Y
{
public Y f()
{
Y y = new SubY_generalist();
...
return y;
}
}
到處使用接口。當(dāng)您只關(guān)心界面的細(xì)節(jié)時(shí),這是最好的,對(duì)于最終用戶來(lái)說(shuō)也是如此。例如,如果您只關(guān)心get和add,則Y可能是List,并且SubY_generalist()可能是ArrayList。
class SubY_mix implements Y
{
public Y f()
{
SubY_mix y = new SubY_mix();
...
return y;
}
}
使用特定類型,但在返回時(shí)隱式擴(kuò)展為通用類型。當(dāng)您實(shí)際上需要使用特定類型的方法,但您的最終用戶永遠(yuǎn)不需要這樣做時(shí),這是最好的。使用前面示例中的ArrayList和,假設(shè)必須調(diào)用,一個(gè)未在 中定義的方法。那么,顯然有必要聲明為。但是,由于最終用戶只需要,因此您應(yīng)該返回并隱式擴(kuò)展。ListftrimToSizeListyArrayListListy
class SubY_specialist implements Y
{
public SubY_specialist f()
{
SubY_specialist y = new SubY_specialist();
...
return y;
}
}
使用專用類型并返回專用類型。這就是FRAUDVAN的“本質(zhì)”。SubY_specialist由于返回類型允許用戶靈活地處理返回SubY_specialist,或者也可以使用f()接口方面的方式Y(jié)。當(dāng)接口不夠具體而無(wú)法有效使用時(shí)(它們應(yīng)該如此,因?yàn)樗鼈兪浅橄蟮模?,這是非常常見的。例如,在 Java類中,只要方法返回 a ,就會(huì)發(fā)生這種情況。這是因?yàn)閷?shí)施. 每當(dāng)您使用and 、、、或( Implements )時(shí),也會(huì)發(fā)生這種情況。 需要這種行為的原因是界面通常不包含最終用戶有效利用的足夠細(xì)節(jié)。將這些細(xì)節(jié)放在接口中會(huì)導(dǎo)致接口膨脹/污染,這是不可取的。相反,直接使用負(fù)責(zé)這些細(xì)節(jié)的類可以保留具有獨(dú)特功能的類的單一職責(zé)原則(避免被迫在接口的未來(lái)實(shí)現(xiàn)者中實(shí)現(xiàn)冗余)。畢竟,如果您的類實(shí)現(xiàn)了兩個(gè)接口,您要么必須創(chuàng)建一個(gè)擴(kuò)展這兩個(gè)接口的新接口并返回該接口(這很快就會(huì)變得丑陋),要么您可以返回實(shí)現(xiàn)者,并讓最終用戶負(fù)責(zé)他們需要哪個(gè)界面(不難看)。 為什么這種行為如此普遍?這是因?yàn)?,一旦隱藏了最終用戶不需要看到的東西(使用可見性修飾符、封裝和信息隱藏),讓最終用戶以他們選擇的方式與您的實(shí)現(xiàn)進(jìn)行交互實(shí)際上是一個(gè)好主意(即根據(jù)他們聲明變量的接口)。事實(shí)上,我什至聲稱這里的所有示例都符合 FRAUDVAN,其中向用戶公開的“最安全”類型而不是專用類型。在第一個(gè)示例中,界面對(duì)于用戶和最終用戶來(lái)說(shuō)足夠?qū)I(yè)化。在第二個(gè)示例中,對(duì)于用戶來(lái)說(shuō)不夠?qū)I(yè)化,但對(duì)于最終用戶來(lái)說(shuō)足夠?qū)I(yè)化。最后,在這個(gè)例子中,對(duì)于用戶和所有最終用戶來(lái)說(shuō)不夠?qū)iT化,盡管一些最終用戶可能選擇聲明是否適合他們的需要。StreamStreamStreamBaseStreamStringBufferreverseappendreplacedeleteinsertStringBufferCharSequence
YYYYY y = f()Y
所以,這是要點(diǎn):
添加回答
舉報(bào)