说我知道这个example:
double getSpeed() {
switch (_type) {
case EUROPEAN:
return getBaseSpeed();
case AFRICAN:
return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;
case NORWEGIAN_BLUE:
return (_isNailed) ? 0 : getBaseSpeed(_voltage);
}
throw new RuntimeException ("Should be unreachable");
}
显然,我会重构为子类,一切都将在世界上再次正确。但是,如果我有:
double getSpeed() {
switch (_type) {
case EUROPEAN:
inform_gary(_count);
return getBaseSpeed();
case AFRICAN:
increment_package_counter();
transmit_coordinates(_coordinates);
return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;
case NORWEGIAN_BLUE:
return (_isNailed) ? 0 : getBaseSpeed(_voltage);
}
throw new RuntimeException ("Should be unreachable");
}
现在它对子类没用,因为那时我必须将子类紧密地耦合到他们不应该知道的代码上。这个问题有解决方案吗?
答案 0 :(得分:1)
问题的评论稍微改进了一下这个问题;我将回答更新的版本。
我会为每种可能的消息类型创建一个类。这些将继承具有execute
函数的消息接口。
通常,消息需要执行一些需要引用执行环境的操作。由于消息对象不可变时生命更容易,我会将这些引用作为参数传递给execute
函数。
界面:
interface Message
{
void execute(Context context)
}
示例消息:
class RebroadcastMessage : Message
{
private final String content;
private final int timeToLive;
public RebroadcastMessage(String content, int timeToLive) {
this.content = content;
this.timeToLive = timeToLive;
}
void execute(Context context)
{
if (timeToLive > 0)
{
foreach (Peer p in context.Peers)
{
context.send(p, new RebroadcastMessage(content, timeToLive - 1));
}
}
}
}
这使得处理消息变得容易:
messageQueue.take().execute(this.context);
根据下面的讨论,我将解释另一种技术。
有时您希望在消息之间处理状态,但不希望将此逻辑放在消息接收类中。在这些情况下,我建议采用事件驱动设计。
A Session
接收消息(例如来自网络连接)并更新收到的每条消息的所有侦听器。
interface MessageListener
{
void handle(Context context, Message message);
}
interface Session
{
void addListener(MessageListener listener);
}
然后,您可以为所需的每项功能单独实施MessageListener
。
class FruitTracker implements MessageListener
{
private Set<Fruit> stock;
public FruitTracker()
{
stock = new HashSet<>();
}
void handle(Context context, Message message)
{
if (message instanceof StockQueryMessage)
{
context.send(context.getSender(), new StockQuoteMessage(stock));
}
else if (message instanceof StockUpdateMessage)
{
stock = ((StockUpdate)message).getStock();
}
}
}
设置:
val fruitTracker = new FruitTracker();
session.addListener(fruitTracker);