我有一个基本抽象类,它聚合了一个集合中的一堆项目:
abstract class AMyAbstract { ListItems { get; private set; } public AMyAbstract(IEnumerable items) { this.Items = new List (items); } }
有很多子类,让我们为它们命名Foo
,Bar
,Baz
,等他们都是一成不变的.现在我需要一个merge()
方法,它将合并items
两个对象,如下所示:
abstract class AMyAbstract { // ... public AMyAbstract merge(AMyAbstract other) { // how to implement??? } } Foo foo1 = new Foo(new string[] {"a", "b"}); Bar bar1 = new Bar(new string[] {"c", "d"}); Foo fooAndBar = foo1.merge(bar1); // items in fooAndBar now contain: {"a", "b", "c", "d"}
由于对象是不可变的,因此该merge()
方法不应该更改items
字段的状态,而应该返回调用它的类uppon的新对象.我的问题是:如何明智地实施该merge()
方法?
问题1:AMyAbstract
显然不了解子类的特定构造函数(依赖性反转原理),因此我不能(或者我可以)在超类中创建子类的实例.
问题2:每个子类中的实现merge()
方法是很多代码重复(DRY规则).
问题3:将merge()
逻辑提取到一个全新的类并不能解决DRY规则问题.即使使用访客模式,也需要大量复制/粘贴.
上面提到的问题排除了我在阅读有关SOLID之前可能已经实现的任何想法.(从那时起,我的生活一直很悲惨;)
或者是否有一个完全不同的,开箱即用的approch来实现这些对象的合并?
我很欣赏C#,Java甚至PHP的答案.
编辑:我想我遗漏了一条有效的信息:事件虽然有很多不同的子类,但他们可以(应该)只用两种,也许三种方式构建(作为单一责任原则的含义):
无参数构造函数
一个接受一个IEnumerable
参数的构造函数
一个接受数组和其他修饰符的构造函数
如果我可以在构造函数上设置约束 - 例如通过在接口中定义构造函数,这会将访问者模式放回到tablie 上.但这只能在PHP中实现.在Java或C#中,无法强制执行构造函数签名,因此我无法确定如何实例化子类.这是一个很好的规则,因为人们永远无法预测子类的作者如何构建对象,但在这种特殊情况下它可能会有所帮助.所以一个帮助问题是:我可以以某种方式强制实现类的实例化吗?在这个简单的情况下,Builder模式听起来太过分了,还是这样?
你是对的依赖倒置规则和代码重复问题.
您可以在抽象类中编写合并逻辑的核心实现,并给出为派生类创建新实例的任务.在抽象类中创建一个抽象方法,强制所有子项实现它.目的是这个方法是创建一个新的类实例并返回它.超类将使用此方法来获取新实例并进行合并.
生成的java代码看起来像这样
abstract class AMyAbstract { // ... public AMyAbstract merge(AMyAbstract other) { AMyAbstract obj = getNewInstance(); // Do the merge // Return the merged object. } protected abstract AMyAbstract getNewInstance(); } class foo extends AMyAbstract { protected foo getNewInstance() { // Instantiate Foo and return it. } }
希望这可以帮助..