2011-09-07 64 views
0

我有一个数据库表,其中包含一个ID列和一个Name列。我的任务是设计一个接受其中一个ID作为参数Main()的程序。什么是设计这个类层次结构的最佳方法?

粗体是编辑2

我需要使用,必须在数据库中存在该ID,以对应于一些代码运行。表中的每一行都对应着稍微不同的代码,但是它们中的很多代码都是共享的。我需要一个能够尽量减少代码重复的设计。

到目前为止,我所开发的抽象基类有一个抽象的Int32字段ID来执行在数据库中具有其相应ID的派生类。通过这种方式,我可以反思派生类来找到ID与Main()参数匹配的实例并实例化该类。然后,我只需调用Main()中的虚拟方法,该方法运行已定义的派生代码最多。

public abstract class Base { 
    public abstract Int32 Id { get; }  
    public void Foo() { 
     // Do something 
    } 
} 

public class Derived { 
    public override Int32 Id { get { return 42; } } 
    public void Foo() { 
     // Do something more specific 
    } 
} 

有没有人有任何更好的想法如何实现我想要的?我喜欢将ID保留在类定义中的想法,但如果它有意义,我愿意改变它。

谢谢!

编辑:

一件事,我不喜欢,这是我必须反映在每个派生类型和实例化类型检查ID。有没有人有更好的想法如何做到这一点?

+0

这是功课? – Xint0

+0

不,它适用于新的自动化引擎。 –

+0

如果你从数据库的id中查找名字,你会如何处理这个名字。这听起来像你仰望,并通过ID键入代码...为什么要查找名称? – bryanmac

回答

2

不使用属性来定义类的ID,而是使用自定义属性。这样,你不必实例化对象来检查它的ID是什么。

当程序运行时,它可以扫描程序集中所有具有该属性标记的类,并找到具有匹配标识的类,实例化该类,然后运行它的Foo方法。如果您在每次应用程序运行中多次执行这种查找,则可以使用您的自定义属性安装所有类,然后将它们放入字典中,以便通过ID快速查找。

您的代码可能是这个样子:

[AttributeUsage(AttributeTargets.Class)] 
public class CommandAttribute { 
    public CommandAttribute(int id) { 
     ID = id; 
    } 

    public int ID { get; private set; } 
} 

public abstract class Command { 
    public abstract void Execute(); 
} 

[Command(2)] 
public class MyCommand : Command { 
    public override void Execute() { 
     //Do something useful 
    } 
} 

使用自定义属性的另一个优点是,你必须明确地标记的一切,是对被实例化候选者,并通过ID来执行,而不是假设比从你的基地派生的任何东西都是候选人。如果你在类之间共享代码,你可能想为它们制作一个通用的基类,它们是从你的基类派生出来的,但不应该被自己实例化或执行。

我不明白的一件事是,如果要运行的类是由ID标识的,那么“名称”字段的要点是什么?如果您可以决定每个ID的名称,那么您可以使用名称字段作为要执行的类的完全限定类型名称,从而避免必须扫描程序集中的所有类型(或应用程序域,这取决于您的搜索范围)。但是,该设置更容易出现拼写错误。

+0

感谢您使用属性的建议。我绝对忽略了这个想法!不幸的是,我无法更改数据库中的结构和数据,并且名称列中包含不清楚的数据。 –

+0

你知道是否有办法强制派生类必须具有属性? –

+0

本机不在C#中。您可以创建自己的后编译步骤,分析输出程序集,并在不满足这些约束条件时产生错误,但我认为在实践中它可能不会成为问题。此外,通过强制所有通过ID执行的候选对象的类可以用属性标记,而不是依赖于从基础“Command”类派生的所有类都可以这样执行的假设(有些可能仅用作其他命令类的基类,并不打算由ID执行)。 – Nimrand

1

这听起来像你需要实施工厂模式。

我会定义一个接口:

public interface IWidget 
{ 
    void Foo(); 
} 

然后基类:

public abstract class WidgetBase : IWidget 
{ 
    public void Foo() 
    { 
     this.Bar() 
    } 

    protected virtual void Bar() 
    { 
     // Base implementation 
    } 
} 

工厂:

public static WidgetFactory 
{ 
    public static IWidget Create(int id) 
    { 
     // Get class name from id, probably use the name in your database. 
     // Get Type from class name 
     // Get constructor for Type 
     // Create instance using constructor and return it. 
    } 
} 

派生类:

public class DerivedWidget : WidgetBase 
{ 
    protected override void Bar() 
    { 
     // call base implementation 
     base.Bar(); 
     // derived implementation 
    } 
} 

在你的主:

public void Main(int id) 
{ 
    var widget = WidgetBase.Create(id); 
    widget.Foo(); 
} 
+0

单一责任原则!为什么在WidgetBase中实现工厂? – Domenic

0

我喜欢@使用工厂这类任务的XINT0的想法,但我想我还是会有助于另一个答案。

实现您最初的设计是将ID传递给基类的构造如下一个更好的办法:

public abstract class Base { 
    public Int32 Id { get; private set; } 
    protected Base(Int32 id) { 
      this.Id = id; 
    } 
    public void Foo() { 
     // Do something 
    } 
} 

public class Derived : Base { 
    public Derived : base(42) {} 
    public void Foo() { 
     // Do something more specific 
    } 
} 
相关问题