Hier gibt es viele gute Antworten, aber ich finde oft, dass die Verwendung von BEIDEN Schnittstellen und abstrakten Klassen der beste Weg ist. Betrachten Sie dieses erfundene Beispiel:
Sie sind Softwareentwickler bei einer Investmentbank und müssen ein System aufbauen, das Aufträge auf einem Markt platziert. Ihre Benutzeroberfläche erfasst die allgemeinste Vorstellung davon, was ein Handelssystem tut .
1) Trading system places orders
2) Trading system receives acknowledgements
und kann in einer Schnittstelle erfasst werden, ITradeSystem
public interface ITradeSystem{
public void placeOrder(IOrder order);
public void ackOrder(IOrder order);
}
Jetzt können Ingenieure, die am Verkaufsschalter und in anderen Geschäftsbereichen arbeiten, eine Schnittstelle zu Ihrem System herstellen, um ihren vorhandenen Apps Funktionen zur Auftragserteilung hinzuzufügen. Und du hast noch nicht einmal angefangen zu bauen! Dies ist die Stärke von Schnittstellen.
So Sie voran gehen und das System für Bau Aktienhändler; Sie haben gehört, dass Ihr System über eine Funktion verfügt, mit der Sie günstige Aktien finden können, und sind sehr gespannt darauf, diese auszuprobieren! Sie erfassen dieses Verhalten in einer Methode namens findGoodDeals()
, erkennen aber auch, dass es eine Menge chaotischer Dinge gibt, die mit der Verbindung zu den Märkten verbunden sind. Sie können beispielsweise ein öffnen haben SocketChannel
,
public class StockTradeSystem implements ITradeSystem{
@Override
public void placeOrder(IOrder order);
getMarket().place(order);
@Override
public void ackOrder(IOrder order);
System.out.println("Order received" + order);
private void connectToMarket();
SocketChannel sock = Socket.open();
sock.bind(marketAddress);
<LOTS MORE MESSY CODE>
}
public void findGoodDeals();
deals = <apply magic wizardry>
System.out.println("The best stocks to buy are: " + deals);
}
Die konkreten Implementierungen werden viele dieser chaotischen Methoden haben connectToMarket()
, aber es findGoodDeals()
ist alles , was die Händler wirklich interessieren.
Hier kommen abstrakte Klassen ins Spiel. Ihr Chef informiert Sie, dass Devisenhändler auch Ihr System nutzen möchten. Wenn Sie sich die Devisenmärkte ansehen, sehen Sie, dass die Sanitärinstallationen fast identisch mit den Aktienmärkten sind. In der Tat connectToMarket()
kann wörtlich wiederverwendet werden, um eine Verbindung zu Devisenmärkten herzustellen. In findGoodDeals()
der Währungsbranche ist dies jedoch ein ganz anderes Konzept. Bevor Sie also die Codebasis an das Devisen-Zauberkind über den Ozean weitergeben, werden Sie zunächst in eine abstract
Klasse umgestaltet , ohne sie zu findGoodDeals()
beeinträchtigen
public abstract class ABCTradeSystem implements ITradeSystem{
public abstract void findGoodDeals();
@Override
public void placeOrder(IOrder order);
getMarket().place(order);
@Override
public void ackOrder(IOrder order);
System.out.println("Order received" + order);
private void connectToMarket();
SocketChannel sock = Socket.open();
sock.bind(marketAddress);
<LOTS MORE MESSY CODE>
}
Ihr Aktienhandelssystem implementiert, findGoodDeals()
wie Sie bereits definiert haben,
public class StockTradeSystem extends ABCTradeSystem{
public void findGoodDeals();
deals = <apply magic wizardry>
System.out.println("The best stocks to buy are: " + deals);
}
Aber jetzt kann das FX Whiz Kid sein System aufbauen, indem es einfach eine Implementierung findGoodDeals()
für Währungen bereitstellt . Sie muss weder Socket-Verbindungen noch die Schnittstellenmethoden neu implementieren!
public class CurrencyTradeSystem extends ABCTradeSystem{
public void findGoodDeals();
ccys = <Genius stuff to find undervalued currencies>
System.out.println("The best FX spot rates are: " + ccys);
}
Das Programmieren auf eine Schnittstelle ist leistungsstark, aber ähnliche Anwendungen implementieren Methoden häufig auf nahezu identische Weise neu. Durch die Verwendung einer abstrakten Klasse werden Neuimplementierungen vermieden, während die Leistung der Schnittstelle erhalten bleibt.
Hinweis: Man kann sich fragen, warum dies findGreatDeals()
nicht Teil der Benutzeroberfläche ist. Denken Sie daran, dass die Schnittstelle die allgemeinsten Komponenten eines Handelssystems definiert. Ein anderer Ingenieur kann ein VOLLSTÄNDIG VERSCHIEDENES Handelssystem entwickeln, bei dem es ihm egal ist, gute Geschäfte zu finden. Die Benutzeroberfläche garantiert, dass der Sales Desk auch eine Schnittstelle zu seinem System herstellen kann. Daher ist es vorzuziehen, Ihre Benutzeroberfläche nicht mit Anwendungskonzepten wie "Schnäppchen" zu verwickeln.