通过泛型与多态实现代码重用 [英] Code reuse through generics vs polymorphism

查看:120
本文介绍了通过泛型与多态实现代码重用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

重用实现的更好方法是什么:继承还是泛型?

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> {}

泛型方法的弊端:

  1. 乍一看似乎有点复杂.尤其是哪里很糟糕.
  2. 一开始似乎并不熟悉.
  3. DataContractSerialize带来一些乐趣.
  4. 装配体更大.

优点:

  1. 类型安全性:您将无法将ScriptTemplateElement添加到ScriptRunStep.
  2. 不需要从收集项目中转换为具体类型.另外-更好的智能支持. ScriptTemplate.Steps立即属于ScriptTemplateStep,而不是抽象Step.
  3. 遵守Liskov原则:在继承方案中,您在ScriptRun上具有IList集合,但实际上不应该向其中添加ScriptTemplateStep,尽管它显然是一个Step.
  4. 您不必进行覆盖.例如.假设您要在脚本上使用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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆