所以,让我们从一些背景开始[修改为更具体[。]我意识到我可以替换以下内容:
abstract class MessageHandler {
public void handleMessage(Message m) {
validateMessage(m);
processMessage(m);
}
protected void validateMessage(Message m) {
// Default validation logic
}
protected abstract void processMessage(Message m);
}
class FakeMessageHandler extends MessageHandler {
proteced void processMessage(Message m) {}
}
下一段代码:
interface IMessageProcessor {
public void processMessage(Message m);
}
class FakeMessageProcessor implements IMessageProcessor {
public void processMessage(Message m) {}
}
class MessageHandler {
private IMessageProcessor processor;
public MessageHandler(IMessageProcessor processor) {
this.processor = processor;
}
public void handleMessage(Message message) {
validateMessage(message);
processor.processMessage(message);
}
protected void validateMessage(Message message) {
// Default validation logic.
}
}
也就是说,我可以用注入的接口替换抽象方法,以便于测试。现在让我们说设计规定人们可以选择覆盖方法:
class FakeMessageHandler extends MessageHandler {
protected void validateMessage(Message m) {}
protected void processMessage(Message m) {}
}
现在无法使用注入的接口,因为MessageHandler中只有一个抽象方法。但是,我不能强制注入的接口包含方法validateMessage(Message message)
,因为使用抽象类的原始点是定义此方法的默认实现。
为了依赖注入和更容易测试的目的,是否有某种优雅的模式将其转换为组合?
答案 0 :(得分:4)
以下是我对此的看法:
我没有扩展MessageHandler,只有一个MessageHandler类,它是IMessageProcessor和IMessageValidator的组合:
希望我的UML图表正确,已经有一段时间......
无论如何,让我们来看看MessageHandler:
class MessageHandler
{
private IMessageProcessor processor;
private IMessageValidator validator;
public MessageHandler(IMessageProcessor processor)
{
this.processor = processor;
//Use the given processor as validator, if it implements the IMessageValidator-interface
if(IMessageValidator.class.isAssignableFrom(processor.getClass()))
{
this.validator = (IMessageValidator)processor;
}
}
public void setMessageValidator(IMessageValidator validator)
{
this.validator = validator;
}
public void handleMessage(Message message)
{
validateMessage(message);
processor.processMessage(message);
System.out.println("Message " + message + " handled by MessageHandler");
}
protected void validateMessage(Message message)
{
if(validator != null)
{
validator.validateMessage(message);
}
else
{
System.out.println("No IMessageValidator-implementation set, using default validation for message " + message);
}
}
}
MessageHandler有两个私有成员,IMessageProcessor和IMessageValidator(它是处理器和验证器的组合)。验证器可以不设置,在这种情况下,默认验证逻辑将在处理消息时启动。
在此示例中,如果传入的处理器也实现了IMessageValidator接口,则它将用作验证器。这可能是您想要的,因为您可以使用相同的构造函数来使用默认验证或自定义验证逻辑来构建MessageHandler,具体取决于传入的对象是仅实现IMessageProcessor还是IMessageProcessor和IMessageValidator(为方便起见,我已扩展了第三个)接口,来自这些接口的IValidatingMessageProcessor)。如果验证器逻辑是单独实现的(仅实现IMessageValidator),则可以使用setValidator方法进行设置。
不需要扩展MessageHandler,因为您可以单独或在实现处理和验证的单个类中实现处理程序之外的处理和验证-logic。
以下是我使用的课程,希望这会有所帮助:
文本形式:
Message.java:
public class Message
{
private int number;
public Message(int number)
{
this.number = number;
}
public String toString()
{
return "Msg " + number;
}
}
IMessageProcessor.java:
interface IMessageProcessor
{
public void processMessage(Message m);
}
IMessageValidator.java:
public interface IMessageValidator
{
public void validateMessage(Message m);
}
IValidatingMessageProcessor.java:
public interface IValidatingMessageProcessor extends IMessageProcessor, IMessageValidator
{
}
FakeMessageProcessor.java:
public class FakeMessageProcessor implements IMessageProcessor
{
public void processMessage(Message m)
{
System.out.println("Using FakeMessageProcessor to process message " + m);
}
}
FakeMessageValidator.java:
public class FakeMessageValidator implements IMessageValidator
{
public void validateMessage(Message m)
{
System.out.println("Using FakeMessageValidator to validate message " + m);
}
}
FakeMessageProcessorAndValidator.java:
public class FakeMessageProcessorAndValidator implements IValidatingMessageProcessor
{
public void validateMessage(Message m)
{
System.out.println("Using FakeMessageProcessorAndValidator for validating message " + m);
}
public void processMessage(Message m)
{
System.out.println("Using FakeMessageProcessorAndValidator for processing message " + m);
}
}
上述类的简单测试主要(只输出东西):
public class MessageTest
{
public static void main(String[] args)
{
//Using processor implementing only IMessageProcessor, MessageHandler will use default validation
IMessageProcessor processor = new FakeMessageProcessor();
MessageHandler handler = new MessageHandler(processor);
handler.handleMessage(new Message(1));
//Setting separate validator to existing MessageHandler-instance
handler.setMessageValidator(new FakeMessageValidator());
handler.handleMessage(new Message(2));
//Using processor implementing both IMessageProcessor and IMessageValidator
processor = new FakeMessageProcessorAndValidator();
handler = new MessageHandler(processor);
handler.handleMessage(new Message(3));
}
}
输出:
No IMessageValidator-implementation set, using default validation for message Msg 1
Using FakeMessageProcessor to process message Msg 1
Message Msg 1 handled by MessageHandler
Using FakeMessageValidator to validate message Msg 2
Using FakeMessageProcessor to process message Msg 2
Message Msg 2 handled by MessageHandler
Using FakeMessageProcessorAndValidator for validating message Msg 3
Using FakeMessageProcessorAndValidator for processing message Msg 3
Message Msg 3 handled by MessageHandler