我正在寻找一种为接口提供单个入口点的技术,但是每个实现的处理方式都不同。
让我们来看一个例子。
我有几个Instrument
接口的实现。当然,乐器具有一些相似之处(它们制作音乐,与音符和音阶有关),但演奏方式却大不相同。Musician
可以演奏乐器,有天赋的音乐家可以演奏几种乐器:
public interface Musician {
void play(Instrument instrument);
}
public class GiftedMusician implements Musician {
@Override
public void play(Instrument instrument) {
if (instrument instanceof Guitar) {
play((Guitar) instrument);
} else if (instrument instanceof Bass) {
play((Bass) instrument);
} else if (instrument instanceof Piano) {
play((Piano) instrument);
}
}
public void play(Guitar guitar) {
guitar.strumWithPick();
}
public void play(Bass bass) {
bass.pluckString();
}
public void play(Piano piano) {
piano.pressKey();
}
}
我已经找到了使用
instanceof
的解决方案,但是我不确定这是否可行。我正在寻找一种设计模式或其他最佳实践来处理这种情况。编辑:
这个例子当然很简单,让我们使其不那么明显。因为,正如我所说,有许多种乐器以不同的方式演奏。像个低音提琴我如何实现一个演奏普通和低音提琴的
Musician
?public class Contrabass implements Instrument{
public void play(boolean useBow) {
if(useBow)
playWithBow();
else
pluckWithFingers();
}
}
最佳答案
我认为,您应该在Instrument
中声明以下方法:
public void play(Musician musician);
然后,您可以为每种仪器实现不同的实现。
例如:
class Guitar implements Instrument {
@Override
public void play(Musician musician) {
System.out.printf("Musician %s is playing the guitar!%n", musician.getName());
strumWithPick();
}
}
... 等等。
在此示例中,除非您决定使用composition将
GiftedMusician
或多个Instrument
与Musician
关联,否则您的GiftedMusician
类没有什么意义。在后一种情况下,您的
Collection<Instrument>
将具有一个构造函数重载,例如,一个Musician
,而您的Instrument
仅将具有单个Instrument
的构造函数。例如(将
play
作为抽象类,将核心“功能”添加到play
):class Musician {
protected Collection<Instrument> instruments;
Musician(Instrument instrument) {
instruments = new HashSet<Instrument>();
if (instrument != null)
instruments.add(instrument);
}
public String getName() {
// of course
return "J. S. Bach";
}
}
class GiftedMusician extends Musician {
GiftedMusician(Instrument instrument) {
super(instrument);
}
GiftedMusician(Collection<Instrument> instruments) {
super(null);
this.instruments = new HashSet<Instrument>(instruments);
}
}
abstract class Instrument {
protected String name;
public void play(Musician musician) {
System.out.printf("Musician %s is playing %s%n", musician.getName(), name);
}
}
编辑后续问题编辑。
如果您需要在
instanceof
方法中参数化特定的播放技术,而无需重载反模式并返回到play
长列表反模式,则您更有理由对参数Musician
进行参数化Musician
。毕竟,由
play
决定他们想要使用的技术。一旦进入
musician.getCurrentTechnique()
正文,您就可以使播放逻辑适应行中的内容。