4 回答

TA貢獻(xiàn)1827條經(jīng)驗 獲得超9個贊
考?!の鳡柧S拉提供了一個很好的例子,但沒有提到另一個重要方面。
通常,接口的要點不是要有更少的類。我想你熟悉耦合和內(nèi)聚這兩個術(shù)語。您總是希望擁有松散耦合且高度內(nèi)聚的代碼。
這意味著,您不希望類相互依賴(耦合),而是以繼承,多態(tài)性等形式共享一些邏輯。這些概念是質(zhì)量對象導(dǎo)向設(shè)計的一些基本支柱。如果您不熟悉這些主題,絕對值得一讀。
回到這個問題,如果你正在處理一個有很多特殊情況的復(fù)雜邏輯,你通常會有一些重復(fù)。但是,這些問題與其他設(shè)計模式和原則更相關(guān),這些模式和原則僅用于遵守 DRY 原則,并以推廣解決方案方法的方式解決情況。
接口背后的主要思想是為類設(shè)置一個邏輯結(jié)構(gòu),這有助于對象操作的統(tǒng)一性。
想象一個證券交易所系統(tǒng)。
此接口具有一個名為 execute 的方法,該方法將執(zhí)行一些應(yīng)用程序邏輯。
public interface Order{ void execute(); }
可能實現(xiàn)此接口的其他類可能是買入和賣出。它看起來像這樣:
public class Buy implement Order{ @Override public void execute(){ //TODO: Some logic } }
現(xiàn)在,買入和賣出都有類似的代碼,甚至可能有一些重復(fù)的代碼,但更重要的是,當(dāng)它們實現(xiàn)相同的接口時,你可以以統(tǒng)一的方式處理它們。您可以有一些股票管理器類,該類會在某些 . 由此可以得出結(jié)論,在使用此類隊列時,您將能夠在 Order 接口的任何實現(xiàn)上調(diào)用該方法。Queue<Order>
execute()
在前面的論點之上,通過使用接口和一些框架(如Spring),您可以進(jìn)行自動布線。這大大減少了對較低級別實現(xiàn)類的依賴,使您可以更改低級類而不會影響頂級處理程序。這種類型的應(yīng)用程序設(shè)計是面向服務(wù)的體系結(jié)構(gòu) (SOA) 中的常見做法。

TA貢獻(xiàn)1810條經(jīng)驗 獲得超4個贊
Robert 談到了打破依賴關(guān)系,當(dāng)然你甚至可以打破庫存和汽車之間的依賴關(guān)系,但我認(rèn)為這不會給你帶來太多好處,因為你不會跨越架構(gòu)邊界。
最好將靜態(tài)依賴關(guān)系中斷為 ,因為 I/O 是一個架構(gòu)邊界,然后您可以替換汽車或庫存的打印方式,這對于測試非常有用。System.out
打破靜態(tài)依賴關(guān)系
class Car {
private String color;
private Integer numberOfTires;
private PrintStream output = System.out;
void setOutput(PrintStream output){
this.output = Objects.requireNotNull(output);
}
public void printCar() {
output.print("Color: " + color);
output.print("Number of tires: " + numberOfTires);
}
}
現(xiàn)在,您可以在測試中替換輸出以捕獲輸出結(jié)果。
應(yīng)用接口隔離原則
public interface Output {
public void print(String msg);
}
class Car {
private String color;
private Integer numberOfTires;
private Output output = (msg) -> System.out.println(msg);
void setOutput(Output output){
this.output = Objects.requireNotNull(output);
}
public void printCar() {
output.print("Color: " + color);
output.print("Number of tires: " + numberOfTires);
}
}
現(xiàn)在,您唯一的依賴項是輸出接口,該接口在測試中更容易替換或模擬。
這個小小的變化使您的汽車獨立于具體的輸出系統(tǒng),或者正如羅伯特所說,一個細(xì)節(jié)。我還可以想象實現(xiàn)一個 JTextArea輸出,以便輸出可以顯示在 GUI 中。
干凈的體系結(jié)構(gòu)告訴我們,I/O 是一個細(xì)節(jié),我們的業(yè)務(wù)代碼不應(yīng)該依賴于它。似乎汽車和庫存是您的業(yè)務(wù)代碼,因此我向您展示了如何將其與具體的輸出系統(tǒng)分離 - 一個細(xì)節(jié)。
+-----+ uses +--------+ implements +--------------+
| Car | --------> | Output | <------------- | SystemOutput |
+-----+ +--------+ +--------------+
---------> control flow ------------->
我們還應(yīng)用了依賴關(guān)系反轉(zhuǎn)原則,因為源代碼依賴關(guān)系指向控制流。

TA貢獻(xiàn)1842條經(jīng)驗 獲得超13個贊
據(jù)推測,您的是“車輛庫存”,而不是“一輛汽車和一輛卡車的庫存”。Inventory
考慮到這一點,也許這會有所幫助:
Car
是一個Vehicle
Truck
是一個Vehicle
Inventory
取決于 -- 而不是 or ,它對這些類型的一無所知Vehicle
Car
Truck
Vehicle::printDetails
由 和 實現(xiàn)Car
Truck
.
public class Scratch4 {
public static void main(String args[]) throws Exception {
Car car = new Car("Blue", 4);
Truck truck = new Truck();
Inventory inventory = new Inventory();
inventory.addVehicle(car);
inventory.addVehicle(truck);
inventory.printVehicleDetails();
}
}
interface Vehicle {
void printDetails();
}
class Car implements Vehicle {
private String color;
private Integer numberOfTires;
public Car(String color, Integer numberOfTires) {
this.color = color;
this.numberOfTires = numberOfTires;
}
public void printDetails() {
System.out.println("Color: " + color);
System.out.println("Number of tires: " + numberOfTires);
System.out.println();
}
}
class Truck implements Vehicle {
@Override
public void printDetails() {
System.out.println("Some kind of truck");
System.out.println();
}
}
class Inventory {
private List<Vehicle> vehicles = new ArrayList<>();;
public void addVehicle(Vehicle vehicle) {
vehicles.add(vehicle);
}
public void printVehicleDetails() {
vehicles.forEach(Vehicle::printDetails);
}
}
收益 率
Color: Blue
Number of tires: 4
Some kind of truck

TA貢獻(xiàn)1802條經(jīng)驗 獲得超6個贊
在生產(chǎn)環(huán)境中的運行時,B 將使用真正的類 A(或?qū)崿F(xiàn)相同接口的另一個類),因此無需復(fù)制代碼。
使用接口可以將另一個實現(xiàn)用于其他用途,例如,使用內(nèi)存中的輕量級假類 A 進(jìn)行 B 類的單元測試,從而避免重磅實類 A。
您(只能)打破“靜態(tài),構(gòu)建時”的依賴關(guān)系。“動態(tài),運行時”依賴項(始終)保留。
在代碼中:
public interface AInterface {}
public class A implements AInterface {}
public class B {
AInterface a;
public B(AInterface a) {
this.a = a;
}
}
public class Main {
B b = B(A());
}
public class AFake implements AInterface {}
public class BTest {
B b = B(AFake())
}
此示例使用構(gòu)造函數(shù)依賴關(guān)系注入。
添加回答
舉報