【问题标题】:Is there a more elegant way (or a pattern) to implement groups of related classes是否有更优雅的方式(或模式)来实现相关类的组
【发布时间】:2012-12-16 10:35:51
【问题描述】:

我正在尝试实现各种相关类组,有点像这样:

  • MySQL数据库
  • MySQLTable(引用 MySQLDatabase)
  • MySQLRecord(引用 MySQLTable)
  • PostGre 数据库
  • PostGreTable(引用 PostGreDatabase)
  • PostGreRecord(引用 PostGreTable)
  • Oracle 数据库
  • ...

由于相关类(MySQLTable、PostGreTable 等)有很多共享代码,因此我使用抽象父类和泛型实现了这一点,如下所示:

class Database {}

class Table<DatabaseType> where DatabaseType : Database 
{
  public DatabaseType FDatabase; //this is what I mean by "references"
}

class Record<TableType, DatabaseType> where 
  DatabaseType : Database
  TableType : Table<DatabaseType> 
{
  public TableType FTable;
}

class MySQLDatabase : Database {}

class MySQLTable : Table<MySQLDatabase> 
{
  public string FCharset;
}

MySQLRecord : Record<MySQLTable, MySQLDatabase> {}

...

而且我需要这种架构能够:

  • 防止错误引用。

例如:MySQLTable 不能引用 PostGreDatabase 或 OracleDatabase,只能引用 MySQLDatabase。

  • 使程序员无需强制转换即可访问对象的特定属性。

例子:

SomeMySQLRecord.FTable.FCharset = 'UTF-8'; 

而不是

((MySQLTable)SomeMySQLRecord.FTable).Charset = 'UTF-8'; 

我正在寻找一种更优雅的方式(或模式)来做到这一点,因为真正的类组有 3 个以上的类,而泛型真的让代码变得很糟糕。示例:

MyType : Type1<GType1, GType2, GType3, GType4> where
  GType1 : Type2,
  GType2 : Type3<GType1>,
  GType3 : Type4<GType1, GType2>,
  GType4 : Type5<GType2, GType1, Type2, GType3>

【问题讨论】:

    标签: oop class design-patterns generics


    【解决方案1】:

    泛型对我来说没有意义。获取您自己的代码:

    Table<DatabaseType : Database>
    MySQLTable : Table<MySQLDatabase>
    

    假设 MySQLTable 也使用泛型定义,因为您将其定义为 Table 的子级:

    MySQLTable<Something> : Table<MySQLDatabase>
    

    你会如何在这里定义 Something?这没有意义。

    如果您使用泛型来实现此目的:

    例如:MySQLTable 不能引用 PostGreDatabase 或 OracleDatabase,只能引用 MySQLDatabase。

    我认为这不是使用泛型的充要条件。

    【讨论】:

    • 是的,我正在使用泛型来实现这一点,因为我能想到的另外两个替代方案是:复制粘贴很多我的代码,只更改类型或声明属性使用抽象类型,例如在 MySQLRecord 而不是 MySQLTable 属性上具有 Table 属性,并进行大量样板类型验证以确保该属性只能接受 MySQLTable。两者都违反了 DRY 原则。
    【解决方案2】:

    我会采取稍微不同的路线,尽管我不完全确定这是否适用于您的特定情况:

         public class Provider { }
    
        public class Oracle : Provider { }
    
        public class AbstractDatabase<T> where T : Provider
        {
            // Your base code here
        }
    
        public class AbstractTable<T> where T : Provider
        {
            public AbstractDatabase<T> FDatabase { get; set; }
            // Your base code here
        }
    
        public class AbstractRecord<T> where T : Provider
        {
            public AbstractTable<T> FTable { get; set; }
        }
    
        public class OracleDatabase : AbstractDatabase<Oracle> { }
    
        public class OracleTable : AbstractTable<Oracle>
        {
            public new OracleDatabase FDatabase { get; set; }
    
            // Your strongly typed code
            public OracleTable(OracleDatabase parent) { }
        }
    

    【讨论】:

    • 但泛型的蔓延依然存在
    • 我明白了,你能举出更具体的例子吗?我只是想看看这样做是否会减少它。
    • 好的,我认为在这个解决方案中你不会看到这个链接问题,因为你最终会得到如下代码: OracleRecord : AbstractRecord 等......而在你的情况下你必须提供两个参数,然后提供三个,等等......使用此解决方案,始终只提供一个参数就足够了 - 提供者类型
    • 能否将我的 FDatabase 和 FTable 字段添加到您的代码中,以便我更好地理解您的解决方案?
    • 不会。我试图避免将 OracleTable.FDatabase 转换为 OracleDatabase。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 2012-01-29
    • 2016-01-23
    • 1970-01-01
    • 2022-06-11
    • 1970-01-01
    相关资源
    最近更新 更多