我有一个数据库表,其中包含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 :(得分:2)
使用自定义属性,而不是使用属性来定义类的ID。这样,您不必实例化对象以检查其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的名称,那么您可以使用name字段作为要执行的类的完全限定类型名称,这样就可以避免扫描程序集(或应用程序域)中的所有类型,取决于您的搜索范围)。但是,这种设置更容易出现拼写错误。
答案 1 :(得分: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();
}
答案 2 :(得分:0)
我喜欢@Xint0关于使用Factory进行此类任务的想法,但我认为我还会提供另一个答案。
实现原始设计的更好方法是将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
}
}