令人惊讶的是,这里给出的许多示例/解释都没有为使用抽象类提供好的论据。仅仅将公共字段/方法放在超类中并不要求它是抽象的。另外(开始咆哮),对于那些所谓的知识渊博的工程师仍然提出动物/车辆/图形层次结构来“解释”面向对象的概念感到羞耻。这些类型的示例非常具有误导性,因为它们指向错误的方向;您通常不应该支持直接子类化,因为它会在类之间创建非常紧密的耦合。而是使用协作(咆哮结束)。
那么我认为抽象类的好用例是什么?我最喜欢的示例之一是“模板方法”GoF 模式的应用。在这里,您希望指定一次算法的通用流程,但允许单个步骤的多次实现。这里我只是将一个包含主要病毒扫描算法(查找下一个病毒,删除或报告它,继续直到扫描完成)的 VirusScanEngine 和一个实现所需算法步骤(findVirus,deleteVirus 和 reportVirus)的 LinearVirusScanner 放在一起的示例)。对于这种可怕的简化,我向所有真正致力于病毒扫描软件的开发人员道歉。
import java.util.Arrays;
public abstract class VirusScanEngine {
public static void main(String[] args) {
byte[] memory = new byte[] { 'a', 'b', 'c', 'M', 'e', 'l', 'i', 's', 's',
'a' , 'd', 'e', 'f', 'g'};
System.out.println("Before: " + Arrays.toString(memory));
new LinearVirusScanner().scan(memory, Action.DELETE);
System.out.println("After: " + Arrays.toString(memory));
}
public enum Action {
DELETE, REPORT
};
public boolean scan(byte[] memory, Action action) {
boolean virusFound = false;
int index = 0;
while (index < memory.length) {
int size = findVirus(memory, index);
if (size > 0) {
switch (action) {
case DELETE:
deleteVirus(memory, index, size);
break;
case REPORT:
reportVirus(memory, index, size);
break;
}
index += size;
}
index++;
}
return virusFound;
}
abstract int findVirus(byte[] memory, int startIndex);
abstract void reportVirus(byte[] memory, int startIndex, int size);
abstract void deleteVirus(byte[] memory, int startIndex, int size);
}
和
public class LinearVirusScanner extends VirusScanEngine {
private static final byte[][] virusSignatures = new byte[][] {
new byte[] { 'I', 'L', 'O', 'V', 'E', 'Y', 'O', 'U' },
new byte[] { 'M', 'e', 'l', 'i', 's', 's', 'a' } };
@Override
int findVirus(byte[] memory, int startIndex) {
int size = 0;
signatures: for (int v = 0; v < virusSignatures.length; v++) {
scan: {
for (int t = 0; t < virusSignatures[v].length; t++) {
if (memory[startIndex + t] != virusSignatures[v][t]) {
break scan;
}
}
// virus found
size = virusSignatures[v].length;
break signatures;
}
}
return size;
}
@Override
void deleteVirus(byte[] memory, int startIndex, int size) {
for (int n = startIndex; n < startIndex + size - 1; n++) {
memory[n] = 0;
}
}
@Override
void reportVirus(byte[] memory, int startIndex, int size) {
System.out.println("Virus found at position " + startIndex
+ " with length " + size);
}
}