我的网络应用程序有3层设计
数据层 - >服务层 - >介绍
我的网络应用程序使用这些框架 1)Spring MVC 2)春天 3)Hibernate(Spring Repository)
假设我有PersonEntity(Hibernate - 数据层)
它具有以下不属于数据库的属性)
当此实体推送到服务和视图层时。我应该如何构建所有这些业务逻辑?
所以要管理这个我有3种方法
将实体与@Transient一起使用并填充这些瞬态属性 使用汇编程序/工厂类
创建EntityWrapper
public class PersonWrapper {
private Person person;
private int age;
拥有PersonModel aka POJO并填充数据库值和其他属性 在构建器类中
假设我将使用延迟加载等完整功能,存在安全问题等。 即使对于没有任何特殊属性的实体,我也将应用相同的方法(即我的DomainModelBuilder可能只是通过再次设置每个值来构建PersonModel)
我个人更喜欢第三种方法,因为它更干净,但是一些开发人员抱怨他们正在做额外的工作和额外的处理,因为他们正在重建与实体完全一样的模型。 这就是为什么我认为2方法更好,因为他们不需要做额外的处理,仍然能够分离聚合值
答案 0 :(得分:1)
网站的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());
}
}
但这实际上取决于视图的复杂程度。如果视图需求是直接的,那么编写这样一个包装器是很无聊的,那么你最终会得到一个包装器,每个方法只是委托给包装的实体(假设,状态字典很简单,不需要外部依赖,如从datasource查找,然后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();
}
}
上面的View Adapter旨在
避免在jsp上使用火车残骸代码(在jsp上难以重构,当时模型不稳定)
避免在jsp上使用if / else jsplet代码。我们针对api层开发了验收测试(使测试直接与ui交互成本更高),因此任何自动化测试都没有涵盖jsps。但是,我们为这些ViewAdapter编写了单元测试(更便宜)。
我听过的缺点是
如果有人在将实体传递给ViewAdapter之后更新实体,那么第二种解决方案会引入微妙的不一致(这是一个.net相关的帖子,我现在找不到它)
如果您希望在采用委托getAge()策略时访问延迟加载属性,则可能存在会话关闭异常。这取决于你的持久性基础设施,当我们使用iBATIS时没关系,当我们切换到Hibernate而没有额外的分离时失败了。
最后但并非最不重要的是,应根据您的项目和您的团队做出决定。我不认为有一个通用的解决方案。
希望这会有所帮助:)