设计这个类层次结构的最佳方法是什么
本文关键字:最佳 方法 是什么 层次结构 | 更新日期: 2023-09-27 18:07:41
我有一个数据库表,其中包含一个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。有人对如何做到这一点有更好的想法吗?
不要使用属性来定义类的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字段作为要执行的类的完全限定类型名称,这样就可以避免扫描程序集中的所有类型(或应用程序域,具体取决于搜索范围(。然而,这种设置更容易出现拼写错误。
听起来您需要实现一个工厂模式。
我会定义一个接口:
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();
}
我喜欢@Xinto使用工厂来完成这类任务的想法,但我认为我仍然会给出另一个答案。
实现原始设计的更好方法是将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
}
}