设计这个通用抽象类的最佳方法是什么? (第3部分)

时间:2009-11-05 02:54:48

标签: .net oop .net-2.0

根据上一个问题,我改变了上下文:

我有一个名为Tenant和CustomerList的抽象类。在这种情况下,租户就像多租户应用程序模型的应用程序的所有者,而CustomerList是Customer类的集合。

这两个阶级之间的关系是多对一的关系。

public abstract class Tenant 
{    
  protected Int32 id;    
  protected String name;    
  public Int32 ID { get; set; }    
  public String Name { get; set; }    
  public abstract bool Add();    
  public abstract bool Update();    
  public abstract bool Delete();  
}

public class ApplicationTenant: Tenant
{    
   public ApplicationTenant() { }    
   public override Int32 ID    
   {      
      get { return id; }         
      set { id = value; }    
   }    
   public override String Name    
   { 
     get { return name; }         
     set { name= value; }    
   }    
}

public abstract class CustomerList
{
   protected Tenant tenant;

   public abstract Tenant Tenant {get; set;} 

   public abstract List<Customer> GetAll();   
}

public abstract class CorporateCustomerList : CustomerList
{
   privateT enant tenant;

   public override Tenant Tenant 
   {
     get(return tenant;) ; 
     set(Tenant = tenant);
   }


   public override List<Customer> GetAll()
   {     
      ... calling from data service
      return t;
   }
}

通过上面的OO设计,我们知道List GetAll()的方法;需要被压倒。

但问题是:

1) CorporateCustomer GetAll()的返回值始终为List<CorporateCustomer>.我必须覆盖List<Customer> Get()而不实施并创建另一个跟随方法

public List<CorporateCustomer > GetAll()  {     return ???;  }

2)如果我仍然覆盖上面的这个方法,并且在返回时我只是投了它......它无论如何都无法工作。 ?!!?无法从列表中转换为列表

3)以下属性:

public override Tenant Tenant    
{         
   get { return tenant; }         
   set { tenant= value; }    
}

意味着我必须重写这个BUTI我不是真的使用过这个因为 CorporateCustomer 总是会被用作ApplicationTenant而不是返回NOT Tenant。

public CorporateTenant Tenant    
{         
   get { return corporateTenant; }         
   set { corporateTenant= value; }    
}

这是正确的设计吗?因为它有点浪费抽象。

有些人建议使用Generic抽象类,但我不确定它是否会有所帮助。我确实尝试在方法上使用泛型,但定义的定义需要从顶层的abstrction开始。

由于

3 个答案:

答案 0 :(得分:1)

不幸的是,你遇到过(IMO)C#的两个主要缺陷和陷阱 - 覆盖和通用的共同和反向差异。我将以最明智的顺序解决问题

关于问题3,您不能使用返回SubClass的方法覆盖返回BaseClass的方法。 C#不允许您在覆盖时更改方法参数,即使更改是类型安全的,并且从我收集的内容中也不会很快解决,因为它是一个非常严重的突破性更改,并且依赖于CLR。解决方法是将CustomerList更改为一个接口(应该没问题,因为它只有抽象成员)并执行类似这样的操作(暂时忽略GetAll):

public interface ICustomerList
{
    Tenant Tenant {get; set;}
}

public abstract class CorporateCustomerList : ICustomerList
{
    private CorporateTenant tenant;

    public CorporateTenant Tenant 
    {
        get { return tenant; }
        set { tenant = value; }
    }

    Tenant ICustomerList.Tenant 
    {
        get { return Tenant; }
        set { Tenant = value; }
    }
}

GetAll的另一个问题是List<BaseClass>无法以任何方式转换或转换为List<SubClass> - 这是SO上的常见问题,并且将针对C#4中的通用接口进行解决。有几种解决方法:

  1. 使用数组存储客户,让GetAll返回IList而不是List,并使用上面的显式接口实现覆盖 - 由于历史原因,数组执行支持元素类型协方差(抱歉格式化,降价似乎做了奇怪的事情)

    public interface ICustomerList
    {
        public IList<Customer> GetAll();
    }
    
    public abstract class CorporateCustomerList : ICustomerList
    {
        private CorporateCustomer[] customers;
    
        public IList<CorporateCustomer> GetAll()
        {
            get { return customers; }
            set { customers= value; }
        }
    
        IList<Customer> ICustomerList.GetAll()
        {
            get { return customers; }
            set { customers = value; }
        }
    }
    
  2. 更改GetAll以返回IEnumerable<T>而不是List<T>,然后使用yield return语法将IEnumerable<CorporateCustomer>转换为IEnumerable<Customer>,但稍微使用二传手更复杂...

    public abstract class CorporateCustomerList : ICustomerList
    {
        // as above...
        private CorporateCustomer[] customers;
    
        IEnumerable<Customer> ICustomerList.GetAll()
        {
            get
            {
                foreach (CorporateCustomer c in customers)
                {
                    yield return c;
                }
            }
        }
    }
    
  3. 希望这会给你一些想法......

答案 1 :(得分:0)

这是凌乱的.....我不认为你有清晰的概念吗?称为列表的东西,应该是列表而不是另一个列表的容器?我实际上不确定你要抽象的是什么。租客似乎是错的?

从你的例子中很难说清楚。

但是租户实际上是一个人/实体,其“合同”被称为“租约”.....由于没有足够的背景,我不确定你的其余问题

答案 2 :(得分:0)

另外,只要您在任何应用程序中代表真人,请考虑使用PersonRole类。这样,您可以给任何Person任意数量的职责,而且您不必创建奇怪而精彩的类层次结构。

对于您的示例,您将有几个角色

public class Customer : Role
{
 ...
}

public class CorporateCustomer : Role
{
 ...
}

public class Tenant : Role
{
 ...
}

一个看起来像这样的Person类:

public class Person
{
   Details Details {get;set;}
   IList<Role> Roles {get;set;}
}

使用Role类封装适当的逻辑。