我的真实场景有点难以解释,所以我将其映射到一个更容易识别的领域,比如家庭娱乐设备:
特定的设备可以提供不同的服务:
Panasonic XYZ 可以播放 DVD 和 CD。
索尼 ABC 只能播放 CD。
日立 PQR 可以播放 DVD 和接收电视。
...
...
每项服务(DVD、CD、电视...)都有大多数模型使用的默认实现,但某些模型具有特定服务的自定义版本。
接口(interface)
选择实现 DVD'izable、CD'izable、TV'izable... 契约(Contract)的模型将
导致模型之间有很多代码重复。
单一继承
实现默认服务的单个父类(super class)将允许我为包含其所有自定义行为的每个模型创建一个子类。然而,对于不提供所有类型服务的模型来说,我的父类(super class)会非常笨重和笨重。
多重继承
多重继承具有选择性地合并所需服务并提供默认实现的能力,表面上看起来很理想。与继承引入的耦合相比,我更看重将 PanasonicXYZ 的所有自定义功能集中在一个类中的内聚性。
但我没有使用 C++(而是 PHP),而且我觉得无论如何都有更好的方法。我也不想使用像 mixins 或 5.4 的特征这样的专有扩展。
组成
我看到一个类爆炸,我对一个特定模型的自定义功能分散在多个类中——例如,我需要一个 PanasonicXYZ_CD 类和 PanasonicXYZ_DVD 类,它们只会被 PanasonicXYZ 对象使用。
有更好的结构吗?
编辑:我会仔细考虑一些评论和回答,而不是过早地发表评论。
最佳答案
使用组合 Luke:
对象类代表系统中的一个角色。即使考虑“设备”很自然,但出于 OOP 的目的,最好还是考虑设备的作用:DVD 播放器、电视接收器、CD 播放器等。
单个设备完成所有这些并不重要,考虑对象将要扮演的角色将帮助您以单一职责对象结束:
class SonyTvWithDVDPlayer {
DVDPlayer asDVDPlayer();
Tv asTv();
}
这种方式很容易重构通用功能,您可以拥有一个 GenericDVDPlayer 并在 asDVDPlayer 方法中返回它。
如果你想允许更动态的使用,比如询问 Device 它支持哪些功能,你可以使用一种 Product Trader ,例如:
interface MultifunctionDevice {
<T> T as(Class<T> functionalitySpec) throws UnsupportedFunctionalityException
}
在代码中你可以这样做:
device.as(DVDPlayer.class).play(dvd);
请注意,在这种情况下,“多功能设备”就像一个Product Trader,DVDPlayer.class 是 spec < em="">产品。
有很多不同的方法来实现交易者和规范,一种是使用访客模式。但我发现在很多情况下(当你希望能够动态配置你的“多功能设备”时)你可以这样做:
class MultifunctionDevice {
Iterable<Device> devices;
<T extends Device> T as(Class<T> spec) {
for (Device dev : devices) {
if (dev.provides(spec)) return dev;
}
throw new UnsupportedFunctionalityException(spec);
}
}
这与构建器和流畅的 API 相结合,可以轻松定义不同的设备,而无需类爆炸:
dvdAndTv = new DeviceBuilder("Sony All in one TV and DVD")
.addPart(new SonyDvdPlayer())
.addPart(new SonyTv())
.build();
关于java - 没有类爆炸的选择性组合的良好对象结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8367439/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/
我有一个奇怪的问题:我在rvm上安装了rubyonrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调