Bri*_*128 1 java oop dependency-injection
因此,让我们从一些背景[经过修改以使其更加具体[。我意识到我可以替换以下内容:
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) {}
}
Run Code Online (Sandbox Code Playgroud)
下一段代码:
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.
}
}
Run Code Online (Sandbox Code Playgroud)
也就是说,我可以将抽象方法替换为注入的接口,以简化测试。现在让我们说该设计规定人们可以选择覆盖方法:
class FakeMessageHandler extends MessageHandler {
protected void validateMessage(Message m) {}
protected void processMessage(Message m) {}
}
Run Code Online (Sandbox Code Playgroud)
现在不能使用注入的接口,因为MessageHandler中只有1个抽象方法。但是,我不能强迫注入的接口包含方法,validateMessage(Message message)因为使用抽象类的原始目的是定义此方法的默认实现。
是否存在某种优雅的模式可以将其转换为合成,以便进行依赖注入和更轻松的测试?
这是我的看法:
除了扩展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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
MessageHandler具有两个私有成员,即IMessageProcessor和IMessageValidator(由处理器和验证程序组成)。可以不设置验证器,在这种情况下,处理消息时将使用默认验证逻辑。
在此示例中,如果传入的处理器还实现IMessageValidator-interface,它将用作验证器。这可能就是您想要的,因为您可以使用同一构造函数使用默认的验证或自定义验证逻辑来构建MessageHandler,具体取决于传入的对象仅实现IMessageProcessor还是同时实现IMessageProcessor和IMessageValidator(为方便起见,我扩展了第三个接口,这些接口中的IValidatingMessageProcessor)。如果验证器逻辑是单独实现的(仅实现IMessageValidator),则可以使用setValidator-method对其进行设置。
无需扩展MessageHandler,因为您可以在处理程序外部实现处理和验证-logic,既可以单独实现,也可以在实现处理和验证的单个类中实现。
这是我使用过的类,希望对您有所帮助:
文字形式:
Message.java:
public class Message
{
private int number;
public Message(int number)
{
this.number = number;
}
public String toString()
{
return "Msg " + number;
}
}
Run Code Online (Sandbox Code Playgroud)
IMessageProcessor.java:
interface IMessageProcessor
{
public void processMessage(Message m);
}
Run Code Online (Sandbox Code Playgroud)
IMessageValidator.java:
public interface IMessageValidator
{
public void validateMessage(Message m);
}
Run Code Online (Sandbox Code Playgroud)
IValidatingMessageProcessor.java:
public interface IValidatingMessageProcessor extends IMessageProcessor, IMessageValidator
{
}
Run Code Online (Sandbox Code Playgroud)
FakeMessageProcessor.java:
public class FakeMessageProcessor implements IMessageProcessor
{
public void processMessage(Message m)
{
System.out.println("Using FakeMessageProcessor to process message " + m);
}
}
Run Code Online (Sandbox Code Playgroud)
FakeMessageValidator.java:
public class FakeMessageValidator implements IMessageValidator
{
public void validateMessage(Message m)
{
System.out.println("Using FakeMessageValidator to validate message " + m);
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
上述类的简单测试主要工具(仅输出内容):
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));
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
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
Run Code Online (Sandbox Code Playgroud)