Spring 混淆:域模型vs实体/@transcent vs EntityWrapper

Spring 混淆:域模型vs实体/@transcent vs EntityWrapper,spring,hibernate,spring-mvc,domain-driven-design,Spring,Hibernate,Spring Mvc,Domain Driven Design,我的web应用程序有三层设计 数据层->服务层->表示 我的web应用程序使用这些框架 1) 春季MVC 2) 弹簧 3) Hibernate(Spring存储库) 问题/困境陈述 假设我有个性(Hibernate-数据层) 它具有以下属性,这些属性不是来自数据库) 年龄,从出生日期开始计算(假设这是复杂的 计算您无法使用.js在视图上执行此操作) 映射到查找字典的状态指示符(即S-Single, M-已婚-D-离婚) 其他一些与业务相关的属性 当该实体被推送到服务和视图层时。我应该如何构建

我的web应用程序有三层设计

数据层->服务层->表示

我的web应用程序使用这些框架 1) 春季MVC 2) 弹簧 3) Hibernate(Spring存储库)

问题/困境陈述 假设我有个性(Hibernate-数据层)

它具有以下属性,这些属性不是来自数据库)

  • 年龄,从出生日期开始计算(假设这是复杂的 计算您无法使用.js在视图上执行此操作)
  • 映射到查找字典的状态指示符(即S-Single, M-已婚-D-离婚)
  • 其他一些与业务相关的属性
当该实体被推送到服务和视图层时。我应该如何构建所有这些业务逻辑

因此,要解决这个问题,我有3种方法

  • 将实体与@Transient一起使用,并填充这些Transient属性 使用汇编程序/工厂类

  • 创建EntityWrapper

    public class PersonWrapper {
    
    private Person person;
    
    private int age;
    
  • 拥有一个PersonModel aka POJO并填充数据库值和其他属性 在建筑工人班

  • 问题: 假设我将使用完整的函数,如延迟加载,则存在安全问题等。 即使对于没有任何特殊属性的实体,我也将应用相同的方法(即我的DomainModelBuilder可能只是通过再次设置每个值来构建PersonModel)

  • 以上哪一项是更好的方法
  • 有没有更正确的方法
  • 我的方法的架构术语是什么?ie域驱动程序设计等
  • 还有别的办法解决我的问题吗
  • 我个人更喜欢第三种方法,因为它更干净,但一些开发人员抱怨说,他们正在做额外的工作和额外的处理,因为他们正在重建与实体完全相似的模型。
    这就是为什么我认为2方法更好的原因,因为它们不需要做额外的处理,并且仍然能够分离聚合值。站点的css/js不起作用,所以答案可能是无格式的

    我更喜欢第二种解决方案。但我使用了一个变体,例如

    public class PersonDetailViewAdapter {
        private Person person
        private PersonStatusDict personStatusDict;
    
        public PersonDetailViewAdapter(Person person, PersonStatusDict personStatusDict) {
             this.person = person;
             this.personStatusDict = personStatusDict;
        }
    
        public String getAge() {//you don't have to use a field
            return person.getAge()//age calculation seems to be a domain logic
        } 
    
        public String getStatusName() {
            return personStatusDict.translate(person.getStatus());
        }
    }
    
    但这实际上取决于你观点的复杂性。编写这样一个包装器是相当枯燥的,如果视图要求是直截了当的,那么您最终会得到一个包装器,每个方法都只是委托给被包装的实体(假设status dict非常简单,不需要外部依赖,例如从数据源查找,那么Person.getStatusName()更方便)。在这种情况下,我会选择第一个解决方案

    下面是我的视图适配器的一个示例:

    public class AirTicketDetailViewAdapter {
    
    private AirTicket ticket;
    
    public AirTicketDetailViewAdapter(AirTicket ticket) {
        this.ticket = ticket;
    }
    
    public String getId() {
        return ticket.getId();//avoid train wreck code
    }
    
    public String getNumber() {
                //avoid dispaly null, this attribute is empty if not ticketed
        return ObjectUtils.nullSafeTrim(ticket.getNumber());
    }
    
    public String getRemark() {
        return ObjectUtils.nullSafeTrim(ticket.getRemark());
    }
    
    public String getTraveler() {
        AirTraveler traveler = ticket.getTraveler();
        String fullName = traveler.passengerType().name() + Constants.SPACE
                + traveler.fullName();
        if (traveler.isInfant()) {
            fullName += Constants.SPACE + "(" + traveler.getCarriedBy() + ")";
        }
        return fullName;
    }
    
    public String getDocumentNumber() {
        AirTraveler traveler = ticket.getTraveler();
        if (traveler.isAdult()) {
            return traveler.getDocument().getNumber();
        } else if (traveler.isChild() || traveler.isInfant()) {
            return DateUtils.format(traveler.getDocument().getDateOfBirth(),
                    Constants.DEFAULT_DATE_PATTERN);
        } else {
            return PassengerType.UNKNOWN.name();
        }
    }
    
    public String getDocumentType() {
        return ticket.getTraveler().getDocument().type().name();
    }
    
    public String getStatusName() {
        return ticket.status().name();
    }
    
    public String getTotalAmount() {
        Money totalAmount = ticket.getTotalAmount();
        return totalAmount.getCurrencySymbol() + totalAmount.getAmount();
    }
    
    }

    上面的视图适配器旨在

  • 避免jsp上的火车失事代码(在jsp上更难重构,当时模型不稳定)

  • 避免在jsp上使用if/else jsplet代码。我们在api层上开发了验收测试(使测试直接与ui交互的成本更高),因此JSP没有包含在任何自动化测试中。但是,我们为这些ViewAdapter编写了单元测试(更便宜)

  • 我听说过的缺点是

  • 第二种解决方案引入了微妙的不一致性,如果有人在实体传递到ViewAdapter后更新了它(这是一篇与.net相关的文章,我现在找不到)

  • 若采用委托getAge()策略,若要访问延迟加载属性,则可能存在会话关闭异常。这取决于您的持久性基础设施,当我们使用iBATIS时还可以,当我们切换到Hibernate而没有额外的dettach时失败了

  • 最后但并非最不重要的一点是,决策应该基于您的项目和团队。我认为没有一刀切的解决方案


    希望这有帮助:)

    尝试+1以获得努力,但当您将BL放入get/set时,我不会认为有问题。当jsp。呈现。。它会多次调用它,最终会浪费大量的处理时间。@user4127抱歉,我不明白。你能详细说明一下吗?BL是指业务逻辑?在我的例子中,getAge()中的“多次调用”是什么?为什么它会被称为多次呢?我今天刚刚实现了这个,非常好,因为我不需要做任何代码更改。。但是我注意到有更多的手动编码来获取helper方法。(是否有一个Eclipse函数来提取出那些需要的?嗯……也许你应该考虑是否在你发现了很多简单的委托方法(例如,GeTiDE())返回Obj.gEdid())时接受这个解决方案,使用瞬态实体解决方案,或者使用一些映射工具(如)如果您坚持将域模型与ui解耦,则填充视图对象。域驱动的设计方法是在数据和服务之间有一个域层,并使Person成为具有所有所需属性(年龄、状态等)的持久性无关域实体