Spring 中的命令模式设计 [已关闭]

Command pattern design in Spring [closed]

提问人:IceMajor 提问时间:11/16/2023 更新时间:11/17/2023 访问量:45

问:


想改进这个问题吗?更新问题,以便可以通过编辑这篇文章用事实和引文来回答。

3天前关闭。

我或多或少地在我的Spring Boot应用程序中实现了命令模式。我仍然有一些疑问,并希望获得第二意见。

我有一个 which - 当给定命令代码时 - 返回一个命令对象的实例,该实例实现功能接口并具有一个名为 .CommandFactoryCommandexecute

下面是一个使用示例:

  • 人员服务:
public Person addChildToPerson(Long personId, Long childId) {
    // acquire a person object from the database given an id
    Person person = (Person) commandFactory.create(GET_PERSON_BY_ID, personId).execute();
    // do the same with child
    Child child = (Child) commandFactory.create(GET_CHILD_BY_ID, childId).execute();
    return (Person) commandFactory.create(ADD_CHILD_TO_PERSON, person, child).execute();
}

现在,这是一个类的代码,该类负责将子项附加到该人并将其保存在数据库中。AddChildToPersonCommand

  • AddChildToPersonCommand:
@RequiredArgsConstructor
public class AddChildToPersonCommand implements Command {

     // declare needed components for performing the command
     private final ChildRepository childRepository;
     private final Person person;
     private final Child child;

     @Override
     public Person execute() {
         // some logic
     }
}

现在,我的疑问主要与执行命令的“声明组件”有关。我不确定对已经使用其他命令检索到的实际对象进行操作是否更好(在示例中:& ),或者只提供 ID 并让它处理其余的工作。GetPersonByIdCommandGetChildByIdCommandAddChildToPersonCommand

一方面,对对象进行操作似乎是一种更好的方法,因为它减少了 的责任。AddChildToPersonCommand

但是,另一方面,当要执行的逻辑不像本示例中那样微不足道时,PersonService 的方法最终可能会变得非常大。

你觉得怎么样?

Java Spring 设计模式

评论

2赞 jaco0646 11/17/2023
我看不出在这里使用命令有什么好处;此外,输出需要类型转换的事实对我来说绝对是无用的。
1赞 IceMajor 11/18/2023
好的,谢谢你。我决定主要出于学习目的实现命令,但我认为当应用程序增长更多时,它们可能会派上用场。你对类型转换的看法是对的,这实际上是一个很大的代码味道,我应该努力解决它。

答:

1赞 jon hanson 11/17/2023 #1

如果通过泛型类型参数捕获返回类型,则可以消除强制转换。例如:

interface Command<T> {
    class Id<T> {}

    T execute();
}

public static final Command.Id<Person> GET_PERSON_BY_ID = new Command.Id<>();
public static final Command.Id<Child> GET_CHILD_BY_ID = new Command.Id<>();
public static final Command.Id<Person> ADD_CHILD_TO_PERSON = new Command.Id<>();

public static class CommandFactory {
    private <T> Command<T> get(Command.Id<T> commandId, Object... args) {
        // Implement...
    }
}

private static final CommandFactory commandFactory = new CommandFactory();

public static class AddChildToPersonCommand implements Command<Person> {
    // ...
}

public Person addChildToPerson(Long personId, Long childId) {
    // acquire a person object from the database given an id
    Person person = commandFactory.get(GET_PERSON_BY_ID, personId).execute();
    // do the same with child
    Child child = commandFactory.get(GET_CHILD_BY_ID, childId).execute();
    return commandFactory.get(ADD_CHILD_TO_PERSON, person, child).execute();
}

TBH:目前尚不清楚您从命令方法中获得了什么好处,而且它似乎增加了不必要的复杂性,并且在对象创建方面很麻烦且有些昂贵。例如,如果 AddChildToPersonCommand 仅将 ChildRepository 存储为字段,并将 Person 和 Child 作为参数传递给 execute 方法,则会更简洁。

Eithr 方式,我认为这个问题更适合 https://codereview.stackexchange.com/

评论

0赞 IceMajor 11/18/2023
谢谢。现在我想起来,它可能更适合代码审查。无论如何,我出于学习目的实现了这种模式,并没有真正考虑它带来的内存复杂性。谢谢你提醒我这一点,althoguh - 正如我提到的 - 这个项目相当学术。我还在项目中使用微服务,可能会使命令模式更加难以使用,但老实说,我非常喜欢这种方法。另外,非常感谢泛型类型参数解决方案。