一般来说,当两个抽象之间的关系是一对多时,策略模式是好的。例如,如果您有一把锁和许多可用于打开锁的钥匙。例如,以下是策略模式的一个很好的例子:
public class Lock {
public void unlock(Key key) {
// Unlock lock if possible
}
}
public interface Key {
public int someState();
}
public class FooKey implements Key {
@Override
public int someState() { ... }
}
public class BarKey implements Key {
@Override
public int someState() { ... }
}
你的问题是一个多对多的问题,有许多锁可以用多把钥匙打开,其中一些钥匙可以用来打开一些锁,而不能打开其他锁。对于这类问题,Visitor Pattern 是一个不错的选择,其中算法是解锁过程,对象是锁。这种方法的好处是成功或失败锁定(特定密钥是否解锁特定锁定)包含在简单的方法中,而无需使用instanceof。
一般来说,使用instanceof 表示需要某种形式的多态性(即,不是测试每个提供的对象以查看它是否是特定类型并基于该类型执行逻辑,而是该类型应该具有多态方法,其行为因对象类型而异)。这个问题太常见了,有一个标准的重构来代替它:Replace Conditional with Polymorphism。
要根据您的目的实施访问者模式,您可以尝试以下类似的方法:
public class UnlockFailedException extends Exception {
public UnlockFailedException(Lock lock, Key key) {
this("Key " + key.getClass().getSimpleName() + " failed to unlock lock " + lock.getClass().getSimpleName());
}
public UnlockFailedException(String message) {
super(message);
}
}
public interface Lock {
public void unlock(Key key);
}
public interface Key {
public void unlock(FacialRecognizer lock) throws UnlockFailedException;
public void unlock(FingerPrintRecognizer lock) throws UnlockFailedException;
}
public class FacialRecognizer implements Lock {
@Override
public void unlock(Key key) {
key.unlock(this);
}
}
public class FingerPrintRecognizer implements Lock {
@Override
public void unlock(Key key) {
key.unlock(this);
}
}
public class FacePhoto extends Key {
@Override
public void unlock(FacialRecognizer lock) throws UnlockFailedException {
// Unlock the lock
}
@Override
public void unlock(FingerPrintRecognizer lock) throws UnlockFailedException {
throw new UnlockFailedException(lock, this);
}
}
public class FingerPrint extends Key {
@Override
public void unlock(FacialRecognizer lock) throws UnlockFailedException {
throw new UnlockFailedException(lock, this);
}
@Override
public void unlock(FingerPrintRecognizer lock) throws UnlockFailedException {
// Unlock the lock
}
}
将每个Lock 的unlock 逻辑分组到一个抽象类中可能很诱人(因为每个Lock 实现都相同),但这会破坏模式。通过将this 传递给提供的Key,编译器知道要调用哪个重载方法。这个过程称为double-dispatch。虽然看起来很乏味,但调用的逻辑很简单(一行),因此虽然有重复,但并不严重。
这种方法的缺点是Key 接口必须为Lock 的每个实现 提供一个unlock 方法。如果缺少一个,编译器会在实现Lock 时抱怨,因为它的unlock 方法将在Key 上调用unlock,它不包含接受新的Lock 实现的方法。从这个意义上说,编译器起到了检查的作用,确保Key 实现可以处理(解锁或解锁失败)每个Lock 实现。
您还可以实现一个包含许多Key 对象的KeyRing,可以使用每个Key 对象解锁Lock,直到找到一个打开Lock 的对象。如果KeyRing上没有Key可以打开Lock,一个UnlockFailedException:
public class KeyRing {
public final List<Key> keys = new ArrayList<>();
public void addKey(Key key) {
keys.add(key);
}
public void removeKey(Key key) {
keys.remove(key);
}
public void unlock(Lock lock) throws UnlockFailedException {
for (Key key: keys) {
boolean unlockSucceeded = unlockWithKey(lock, key);
if (unlockSucceeded) return;
}
throw new UnlockFailedException("Could not open lock " + lock.getClass().getSimpleName() + " with key ring");
}
private boolean unlockWithKey(Lock lock, Key key) {
try {
lock.unlock(key);
return true;
}
catch (UnlockFailedException e) {
return false;
}
}
}
如果UnlockFailedException 过于突兀,可以将Key 的unlock 方法更改为返回一个boolean,表示解锁过程是否成功。例如:
public interface Key {
public boolean unlock(FacialRecognizer lock);
public boolean unlock(FingerPrintRecognizer lock);
}
public class FacePhoto extends Key {
@Override
public boolean unlock(FacialRecognizer lock) {
// Unlock the lock
return true;
}
@Override
public boolean unlock(FingerPrintRecognizer lock) {
return false;
}
}
public class FingerPrint extends Key {
@Override
public void unlock(FacialRecognizer lock) {
return false;
}
@Override
public void unlock(FingerPrintRecognizer lock) {
// Unlock the lock
return true;
}
}
使用boolean返回值也简化了KeyRing的实现:
public class KeyRing {
public final List<Key> keys = new ArrayList<>();
public void addKey(Key key) {
keys.add(key);
}
public void removeKey(Key key) {
keys.remove(key);
}
public boolean unlock(Lock lock) throws UnlockFailedException {
for (Key key: keys) {
boolean unlockSucceeded = lock.unlock(key);
if (unlockSucceeded) return true;
}
return false;
}
}