代码之家  ›  专栏  ›  技术社区  ›  earthling

如何让我的派生类只接受另一个对象的特定派生类型

  •  0
  • earthling  · 技术社区  · 15 年前

    为此,我正在进行OO设计,通过抽象我的服务器和数据库信息来帮助保持驱动程序简单易懂。

    我试过研究几种不同的方法,但这里是我认为最有意义的方法。

    我有我的基础课:

    public abstract class DBServer
    {
        public List<Database> Databases { get; set; }
        public abstract bool MakeBackupCall(Database d);
    }
    

    然后是两个派生类:

    public class DASPServer : DBServer
    {
        public string APIKey { get; set; }
    
        public override bool MakeBackupCall(Database d)
        {
             // do some stuff
             return true;
        }
    }
    
    public class RackspaceServer : DBServer
    {
        public override bool MakeBackupCall(Database d)
        {
            // do some different stuff
            return true;
        }
    }
    

    这个问题与我的相关对象有关 Database . 由于每个主机的备份过程不同,因此我需要不同的数据库信息。例如,对于折扣ASP.net,我需要数据库的版本(2000、2005、2008),以便我知道要调用哪个web服务。对于Rackspace,我需要外部服务器名、数据库用户名和密码来创建连接字符串。因此,我尝试创建具有以下层次结构的数据库对象。

    public abstract class Database
    {
        public string Name { get; set; }     
    }
    
    public class DASPDatabase : Database
    {
        public string Version { get; set; }
    }
    
    public class RackspaceDatabase : Database
    {
        public string ServerName { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }
    
        protected string ConnectionString
        {
            get { return string.Format("Data Source={0};Network Library=;Connection Timeout=30;Packet Size=4096;Integrated Security=no;Encrypt=no;Initial Catalog={1};User ID={2};Password={3}", ServerName, Name, UserName, Password); }
        }
    }
    

    我要做的是,确保我的DASPServer实例总是获得daspdatabase的实例,Rackspace也是如此。或者,如果我走错了方向,我想挨一记耳光。

    非常感谢

    5 回复  |  直到 15 年前
        1
  •  1
  •   Adrian K    15 年前

    我倾向于把数据访问层完全抽象出来——把它放在一个接口后面(基本上是 Dependency Inversion

    Strategy Pattern .

    在这两种情况下,您都可以通过配置选择具体的数据访问实现。

        2
  •  3
  •   Jerod Houghtelling    15 年前

    public abstract class DBServer<TDatabase> where TDatabase : Database
    {
        public List<TDatabase> Databases { get; set; }
        public abstract bool MakeBackupCall( TDatabase d );
    }
    
    public class DASPServer : DBServer<DASPDatabase>
    {
        public string APIKey { get; set; }
    
        public override bool MakeBackupCall( DASPDatabase d )
        {
            // do some stuff
            return true;
        }
    }
    
    public class RackspaceServer : DBServer<RackspaceDatabase>
    {
        public override bool MakeBackupCall( RackspaceDatabase d )
        {
            // do some different stuff
            return true;
        }
    }    
    
        3
  •  1
  •   Thomas Levesque    15 年前

    您可以隐藏 MakeBackupCall :

    public new bool MakeBackupCall(RackspaceDatabase d)
    {
        // Do something
    }
    

    这样,如果在 RackspaceServer 变量,编译器将强制 BackspaceDatabase . 当然,如果在DBServer变量上调用它,它将不起作用,因为基本实现将被调用。。。

    Database

    public abstract class DBServer
    {
        public List<Database> Databases { get; set; }
    
        // Non-virtual; the actual implementation is not done in that method anyway
        public bool MakeBackupCall(Database d)
        {
            return MakeBackupCallCore(d);
        }
    
        // Actual implementation goes there
        protected abstract MakeBackupCallCore(Database d);
    }
    
    public class RackspaceServer : DBServer
    {
        // Hide the base method
        public new bool MakeBackupCall(BackspaceDatabase d)
        {
            return MakeBackupCallCore(d);
        }
    
        // Do the actual implementation here, and ensure it is really a BackspaceDatabase
        protected virtual bool MakeBackupCallCore(Database d)
        {
            BackspaceDatabase bd = d as BackspaceDatabase;
            if (bd == null)
                throw new ArgumentException("d must be a BackspaceDatabase");
    
            // do some different stuff with bd
            return true;
        }
    }
    

    BackspaceServer DbServer 不知道它的实际类型。

    SqlConnection.CreateCommand() SqlCommand DbConnection.CreateCommand() 返回一个 DbCommand CreateDbCommand )

        4
  •  0
  •   Eric Petroelje    15 年前

    只需在运行时检查类型并抛出 ArgumentException

        5
  •  0
  •   TreDubZedd    15 年前

    我不知道有什么方法可以在编译时确保 MakeBackupCall() Database 子类。但是,在运行时,可以检查传递的参数 is 正确的子类型。