Тут є багато чудових відповідей, але я часто вважаю, що використання ОБИХ інтерфейсів та абстрактних класів є найкращим шляхом. Розглянемо цей надуманий приклад:
Ви розробник програмного забезпечення в інвестиційному банку, і вам потрібно створити систему, яка розміщує замовлення на ринку. Ваш інтерфейс захоплює найбільш загальне уявлення про те, що торговельна система робить ,
1) Trading system places orders
2) Trading system receives acknowledgements
і може бути зафіксовано в інтерфейсі, ITradeSystem
public interface ITradeSystem{
public void placeOrder(IOrder order);
public void ackOrder(IOrder order);
}
Тепер інженери, які працюють у відділі продажів та в інших сферах бізнесу, можуть почати взаємодіяти з вашою системою, щоб додати функціональність розміщення замовлень до своїх існуючих додатків. А ви ще навіть не почали будувати! У цьому сила інтерфейсів.
Тож ви продовжуєте будувати систему для біржових трейдерів; вони чули, що у вашій системі є функція пошуку дешевих запасів, і дуже хочуть її випробувати! Ви фіксуєте цю поведінку за допомогою методу, який називається findGoodDeals()
, але також усвідомлюєте, що в підключенні до ринків є багато брудної речі. Наприклад, ви повинні відкрити 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);
}
Конкретні реалізації матимуть багато таких брудних методів connectToMarket()
, але findGoodDeals()
це все, про що трейдери насправді піклуються.
Зараз ось де вступають абстрактні класи. Ваш начальник повідомляє, що торговці валютою також хочуть використовувати вашу систему. І, дивлячись на валютні ринки, ви бачите, що сантехніка майже ідентична фондовим ринкам. Насправді, вони connectToMarket()
можуть бути використані дослівно для підключення до валютних ринків. Однак findGoodDeals()
на валютній арені існує набагато інша концепція. Отже, перед тим, як передати кодову базу дитині- майстру-валютові за океан, ви спочатку переробляєте в abstract
клас, залишаючи findGoodDeals()
нездійсненим
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>
}
Ваша система торгівлі акціями реалізується, findGoodDeals()
як ви вже визначили,
public class StockTradeSystem extends ABCTradeSystem{
public void findGoodDeals();
deals = <apply magic wizardry>
System.out.println("The best stocks to buy are: " + deals);
}
але тепер дитина-фахівець з findGoodDeals()
валютою може побудувати свою систему, просто забезпечивши реалізацію валют; їй не доведеться виконувати підключення сокетів або навіть методи інтерфейсу!
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);
}
Програмування на інтерфейс є потужним, але подібні програми часто повторно впроваджують методи майже однаково. Використання абстрактного класу дозволяє уникнути реалізації, зберігаючи потужність інтерфейсу.
Примітка: можна запитати, чому findGreatDeals()
це не частина інтерфейсу. Пам’ятайте, інтерфейс визначає найзагальніші компоненти торгової системи. Інший інженер може розробити ЦІЛЬКО РІЗНУ торгову систему, де вони не дбають про пошук вигідних пропозицій. Інтерфейс гарантує, що відділ продажів також може взаємодіяти зі своєю системою, тому бажано не заплутувати ваш інтерфейс такими поняттями програм, як "чудові пропозиції".