通过泛型与多态实现代码重用 [英] Code reuse through generics vs polymorphism
问题描述
重用实现的更好方法是什么:继承还是泛型?
What is the better way to reuse implementation: inheritance or generics?
该模型如下:脚本具有步骤,步骤具有元素.树结构是双重链接的,即步骤现在知道其脚本和元素了.
The model is following: Script has Steps, Steps have Elements. Tree structure is double linked, i.e. Steps know their Script and Elements now their Step.
现在,有两种类型的脚本:模板和运行,其中首先创建运行作为模板的副本.这将导致2个相似的层次结构ScriptTemplate-> ScriptTemplateStep-> ScriptTemplateElement和ScriptRun-> ScriptRunStep-> ScriptRunElement.大多数功能是通用的,但是各种类可能具有一些其他属性.
Now, there are 2 types of Scripts: Templates and Runs, where a Run is created at first as a copy of the Template. This results in 2 similar hierarchies ScriptTemplate->ScriptTemplateStep->ScriptTemplateElement and ScriptRun->ScriptRunStep->ScriptRunElement. Most of the functionality is common, but various classes may have some additional properties.
要重用功能,我可以开发抽象的Script类,该类由ScriptRun和ScriptTemplate派生,例如:
To reuse functionality I could develop abstract Script class which would be derived by ScriptRun and ScriptTemplate like:
abstract class Script { IList<Step> Steps; }
class ScriptRun : Script {}
class ScriptTemplate : Script {}
class Step { Script Script; IList<Element> Elements; }
class ScriptRunStep : Step {}
class ScriptTemplateStep : Step {}
或者我可以尝试泛型:
abstract class Script<TScript, TStep, TElement>
where TScript:Script<TScript, TStep, TElement>
where TStep:Step<TScript, TStep, TElement>
where TElement:Element<TScript, TStep, TElement>
{ IList<TStep> Steps; }
abstract class Step<TScript, TStep, TElement>
where TScript:Script<TScript, TStep, TElement>
where TStep:Step<TScript, TStep, TElement>
where TElement:Element<TScript, TStep, TElement>
{ TScript Script; IList<TElement> Elements; }
class ScriptRun : Script<ScriptRun, ScriptRunStep, ScriptRunElement> {}
class ScriptRunStep : Step<ScriptRun, ScriptRunStep, ScriptRunElement> {}
class ScriptRunElement : Element<ScriptRun, ScriptRunStep, ScriptRunElement> {}
class ScriptTemplate : Script<ScriptTemplate, ScriptTemplateStep, ScriptTemplateElement> {}
class ScriptTemplateStep : Step<ScriptTemplate, ScriptTemplateStep, ScriptTemplateElement> {}
class ScriptTemplateElement : Element<ScriptTemplate, ScriptTemplateStep, ScriptTemplateElement> {}
泛型方法的弊端:
- 乍一看似乎有点复杂.尤其是哪里很糟糕.
- 一开始似乎并不熟悉.
- DataContractSerialize带来一些乐趣.
- 装配体更大.
优点:
- 类型安全性:您将无法将ScriptTemplateElement添加到ScriptRunStep.
- 不需要从收集项目中转换为具体类型.另外-更好的智能支持. ScriptTemplate.Steps立即属于ScriptTemplateStep,而不是抽象Step.
- 遵守Liskov原则:在继承方案中,您在ScriptRun上具有IList集合,但实际上不应该向其中添加ScriptTemplateStep,尽管它显然是一个Step.
- 您不必进行覆盖.例如.假设您要在脚本上使用NewStep方法.在前一种情况下,您说
:
abstract class Script { abstract Step NewStep(); }
abstract class ScriptRun {
override Step NewStep(){
var step = new ScriptRunStep();
this.Steps.Add(step);
return step;
}
}
abstract class ScriptTemplate {
override Step NewStep(){
var step = new ScriptTemplateStep();
this.Steps.Add(step);
return step;
}
}
在泛型方案中,您编写:
In the generics scenario you write:
abstract class Script<TScript, TStep, TElement>
where TScript:Script<TScript, TStep, TElement>
where TStep:Step<TScript, TStep, TElement>, new()
where TElement:Element<TScript, TStep, TElement>
{
TStep NewStep() {
var step = new TStep();
this.Steps.Add(step);
return step;
}
}
并且ScriptRun和ScriptTemplate自动具有该方法,或者甚至更好的方法:返回类型分别为ScriptRunStep和ScriptTemplateStep而不是简单的Step.
and ScriptRun and ScriptTemplate automatically have that method, or an even better one: with a return type of respectively ScriptRunStep and ScriptTemplateStep instead of simply a Step.
推荐答案
我发现,泛型通过泛型属性促进了合成,而不必为要利用的每个合成编写不同的类,也不必创建冗长的继承树.在可能的情况下,我会尽量主张使用组合继承,尤其是在单继承平台中.
I find that generics facilitate composition through generic properties without having to write different classes for each composition you want to leverage or having to create a lengthy inheritance tree. I try to favor composition to inheritance when I can, especially in a single-inheritance platform.
我要说,您的情况需要两者兼而有之.也许像下面这样:
I'd say your situation warrants a little bit of both. Perhaps something like the following:
class Child<TParent> { TParent Parent; }
class Parent<TChild> { IList<TChild> Children; }
class ParentAndChild<TParent, TChild> : Parent<TChild> { TParent Parent; }
class Element : Child<Step> { ... }
class Step : ParentAndChild<Script, Element> { ... }
class Script : Parent<Step> { ... }
像这样的事情可以促进双向链接对象的层次结构中的许多功能.
Something like this could facilitate much of the functionality in a hierarchy of double-linked objects.
这篇关于通过泛型与多态实现代码重用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!