为了账号安全,请及时绑定邮箱和手机立即绑定

DDD - 复合聚合序列化 - 设计问题

DDD - 复合聚合序列化 - 设计问题

互换的青春 2023-08-16 10:00:13
我正在尝试将 DDD 应用于一个 Java 项目。这是我偶然发现的问题:在域中,我有一个使用复合 OOP 模式实现的聚合。该聚合上的方法会生成一些需要序列化并通过线路发送的域对象。这些是我想到的选项:在我的域的应用程序服务部分中,我正在聚合,调用它的方法,并尝试将结果序列化到 DTO。为了将其序列化为 DTO,我必须instanceof检查当前节点是复合节点还是子节点,然后继续序列化。由于instanceof代码味道(正如我读到的,它违反了打开/关闭原则等),我决定尝试使用访问者模式。为了应用访问者模式,我的复合聚合必须实现访问者,它将返回 DTO,然后 DTO 成为域层的一部分 - 这也不是一个好的设计(因为域应该只包含域概念,而 DTO 不属于其中) 。DTO 序列化只是技术细节,不应该进入领域层。还有其他不违背这些设计原则的解决方案吗?有没有办法在java中模拟重载方法的动态绑定(除了instanceof- 因为这可以解决我使用选项1的问题)?
查看完整描述

3 回答

?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

如果访问者具有通用返回类型,则访问的类不会与该类型耦合。


public interface Node {

    <T> T accept(NodeVisitor<T> visitor);

}


public class ANode implements Node {

    @Override

    public <T> T accept(NodeVisitor<T> visitor) {

        return visitor.visit(this);

    }

}


public class BNode implements Node {

    @Override

    public <T> T accept(NodeVisitor<T> visitor) {

        return visitor.visit(this);

    }

}


public interface NodeVisitor<T> {

    T visit(ANode aNode);

    T visit(BNode bNode);

}


public class DtoNodeVisitor implements NodeVisitor<DTO> {

    @Override

    public DTO visit(ANode aNode) {

        return new DTO(); //use ANode to build this.

    }

    @Override

    public DTO visit(BNode bNode) {

        return new DTO(); //use BNode to build.

    }

}

ANode并且BNode对这里一无所知DTO。


查看完整回答
反对 回复 2023-08-16
?
九州编程

TA贡献1785条经验 获得超4个赞

首先,在第 2 点中我不明白:


我的复合聚合必须实现访客


我想到的第一个问题是,为什么?您不能将访问者声明为接口,并将实现作为聚合的输入参数传递吗?


有没有办法在java中模拟重载方法的动态绑定(除了instanceof - 因为这可以解决我使用选项1的问题)?


是的,您可以使用反射来做到这一点,但真正的问题是,您想使用它们吗?


我认为答案取决于您需要管理多少案例以及它们发生变化的频率?


如果您有“可管理”数量的不同案例,则解决方案instanceof可以是一个很好的交易:


public Something myMethod(Entity entity){

    if (entity instanceof AnEntity){

         //do stuffs

    else if (entity instanceof AnotherEntity){

         //do something else

    ...

    else {

         throw new RuntimeException("Not managed " + entity.getClass().getName());

    }

}

否则,当您有更多情况并希望将代码拆分为自己的方法时,您可以使用 Java 来完成MethodHandle,让我发布一个用法示例:


package virtualmethods;


import java.lang.invoke.MethodHandles;

import java.lang.invoke.MethodType;


public class MyObject {


    public String doStuffs(Object i) throws Throwable {

        try {

            final MethodType type = MethodType.methodType(String.class, i.getClass());

            return (String) MethodHandles.lookup()

                .findVirtual(getClass(), "doStuffs", type)

                .invoke(this, i);

        } catch (NoSuchMethodException e) {

            throw new RuntimeException("Not managed " + i.getClass().getName(), e);

        }

    }


    private String doStuffs(Integer i) {

        return "You choose " + i;

    }

    private String doStuffs(Boolean b) {

        return "You choose boolean " + b;

    }

}

然后使用它:


package virtualmethods;


public class Main {


    public static void main(String[] args) throws Throwable {


        MyObject object = new MyObject();


        System.out.println("Integer => " + object.doStuffs(5));

        System.out.println("Boolean => " + object.doStuffs(true));

        try {

            System.out.println("String => " + object.doStuffs("something"));

        }

        catch (Throwable e) {

            System.out.println("KABOOM");

            e.printStackTrace();

        }

    }


}

获取an 的公共方法将查找以结果命名的方法并作为类中的输入(更多信息请参见此处)。 使用这种方式,您可以在运行时分派方法(使用重载是在编译时静态链接)。但这两种方法都存在一个问题,即您无法确定您将管理第一种情况和/或第二种情况中扩展/实现的所有类型,两种解决方案都有一个或一个来检查何时传递非托管类型到方法。MyObjectObjectdoStuffsStringi.getClass()MyObject

EntityObjectelsecatch

百分百确定您正在管理所有类型只能使用@jaco0646提出的解决方案来实现,据我所知,它强制您管理所有类型,否则它将无法编译。考虑到它需要的样板数量,我只会在抛出会RuntimeException导致业务问题时使用,并且我不能保证它不会使用适当的测试来抛出(除此之外,我发现它非常有趣)。


查看完整回答
反对 回复 2023-08-16
?
一只名叫tom的猫

TA贡献1906条经验 获得超2个赞

听起来你把它过于复杂化了。如果您需要,typeof那么您的聚合不会返回有效的域对象。它返回的域对象太通用。为了解决这个问题,您可以将聚合方法分为两种方法;一个返回 Child,另一个返回 Composite。然后,您的应用程序服务决定调用哪一个(如果可能)。

如果由于某种原因您需要聚合返回通用对象,我会重新考虑您选择的设计。

另一个“黑客”是简单地在域对象上放置一个属性来指示它是复合对象还是子对象。我假设聚合会知道它是否是并且能够准确地填充该属性。


查看完整回答
反对 回复 2023-08-16
  • 3 回答
  • 0 关注
  • 93 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信