java - 我可以用组合代替这种继承吗?

标签 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) {}
}

下一段代码:

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.
  }
}

也就是说,我可以用注入(inject)的接口(interface)替换抽象方法,以便于测试。现在假设设计规定人们可以选择性地重写这些方法:

class FakeMessageHandler extends MessageHandler {
  protected void validateMessage(Message m) {}
  protected void processMessage(Message m) {}
}

注入(inject)的接口(interface)现在无法使用,因为MessageHandler 中只有1 个抽象方法。然而,我不能强制注入(inject)的接口(interface)包含方法 validateMessage(Message message),因为使用抽象类的初衷是定义此方法的默认实现。

是否有某种优雅的模式可以将其转换为组合以实现依赖注入(inject)和更轻松的测试?

最佳答案

这是我的看法:

我没有扩展 MessageHandler,而是有一个 MessageHandler 类,它是 IMessageProcessor 和 IMessageValidator 的组合: Class diagram

希望我的 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 有两个私有(private)成员,IMessageProcessor 和IMessageValidator(它是处理器和 validator 的组合)。 Validator 可以不设置,在这种情况下,默认验证逻辑将在处理消息时启动。

在这个例子中,如果传入的处理器也实现了 IMessageValidator 接口(interface),它将被用作 validator 。这可能是您想要的,因为您可以使用相同的构造函数来使用默认验证或自定义验证逻辑构建 MessageHandlers,具体取决于传入的对象是仅实现 IMessageProcessor 还是同时实现 IMessageProcessor 和 IMessageValidator(为方便起见,我扩展了第三个接口(interface),来自这些接口(interface)的 IValidatingMessageProcessor)。如果 validator 逻辑是单独实现的(仅实现 IMessageValidator),则可以使用 setValidator 方法进行设置。

无需扩展 MessageHandler,因为您可以在处理程序外部同时实现处理和验证逻辑,既可以单独实现,也可以在实现处理和验证的单个类中实现。

以下是我用过的类,希望对你有帮助:

Zip-package in MediaFire

文本形式:

消息.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

关于java - 我可以用组合代替这种继承吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8848066/

相关文章:

javascript - 在面向对象的 Javascript 文件上使用 jQuery

ios - 实现MVC设计的难度(iOS游戏)

java - 在自己的 Java 框架中支持多个 DI 容器

spring-boot - Spring Boot 依赖注入(inject)如何使用不同类型的注解

C++ Matrix 类层次结构

c# - Ninject 模块的目的是什么?

java - EclipseLink 错误 : Exception Description: Missing descriptor for class

java - undefined variable 上的 BaseX XQJ API 错误,而变量已定义

java - 通过函数设置字段

Java:空循环