这里有很多很棒的回答,但我通常发现同时使用接口和抽象类是最佳选择。考虑这个人为构造的例子:
你在一家投资银行担任软件开发人员,需要构建一个将订单放入市场的系统。你的接口捕捉了交易系统的最一般概念。
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()
不是接口的一部分。记住,接口定义了交易系统最普遍的组件。另一位工程师可能会开发一个完全不同的交易系统,在那里他们并不关心寻找好的交易。接口保证销售桌面也能与他们的系统接口,因此最好不要将接口与"好的交易"等应用概念纠缠在一起。