1 回答

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