我开发的应用程序包含几个层次。我们有返回模型对象的 DAO 层。我们还有映射器实例化 DTO 对象并将它们发送给客户端。实体映射到 Controller 层中的 DTO。我已经在几个实体类中引入了继承。让我们假设如下图所示
class diagram (not enough reputation points to past image directly)
我向 DAO 询问具体动物园的动物名单。然后我得到列表 List animals,但它们是具体类型,因为 Animal 是抽象的,我们不能在数据库中只有 Animal。我想从这个模型对象创建 DTO。我必须使用映射器,其中我有 if .. else 语句检查每只动物的类型,然后创建适当的 DTO,比如
if (animal instanceof Dog) {
.. create dog dto
} else if (animal instance of Cat) {
.. create cat dto
} .. and so on
这段代码看起来不太好。使用多态性并在每只动物上调用一些方法来生成 DTO 会很好,但是在域模型中创建 DTO 对象的逻辑只是为了通信是不好的。您如何解决此类情况?
编辑: 更具体地说,我想让DTO像 1. DogDTO 仅包含字段颜色和名称 2. 仅包含 numberOfFins 的 FishDTO 没有一个具有所有可能属性的大 AnimalDTO
最佳答案
您想为不同类型的对象选择不同的转换。在 Java 中基本上有两种解决这个问题的方法:
使用 instanceof 或通过从存储库获取对象的类将其映射到专门的 Transformer 对象(可以是简单的 Map
使用访客模式。这种方法的想法是,最简单的方法是在所有域对象中都有一个 toDTO() 方法,但这会在域对象中引入对 DTO 的不必要的依赖。另一种方法是将所有这些类都放在一个对象中能够使用这个,你仍然必须弄清楚你想要转换的对象的类型并调用正确的方法:VM 不能为你做这个。访问者模式就是解决这个问题的设计模式。
访客模式的基本设计是这样的:
public abstract class AnimalVisitor<T> {
public abstract T visit (Dog d);
public abstract T visit (Fish f);
...
}
public abstract class Animal {
public <T> abstract T accept (AnimalVisitor<T> v);
...
}
public class Dog extends Animal {
public <T> T accept (AnimalVisitor<T> v) {
return v.visit(this);
}
...
}
public class Fish extends Animal {
public <T> T accept (AnimalVisitor<T> v) {
return v.visit(this);
}
...
}
public class DTOTransformer extends AnimalVisitor<DTO> {
public DogDTO visit (Dog d) {
return new DogDTO(d);
}
public FishDTO visit (Fish f) {
return new FishDTO(f);
}
}
当你引入一个新的Animal类型时,你需要在AnimalVisitor类中添加一个新的visit方法。系统会提示您执行此操作,因为您必须在新的 Animal 类型中实现 accept 方法。这还将提示您更新 DTOTransformer 和 AnimalVisitor 的任何其他实现。
如您所见,与简单的 instanceof 样式方法相比,此方法需要更多代码。它确实为您提供了一个很好的可扩展机制,用于您希望在您的域上执行的其他类似操作。
我想这真的取决于您的情况,哪种方法最好。但是,我总是建议使用像 Dozer 这样的框架。或 ModdelMapper在编写 if (.. instanceof ...) else if (... myself.
关于java - 多态性和 DTO 对象创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30527947/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象