繁体   English   中英

C#类继承

[英]C# Class Inheritance

我正在使用保险,有两种不同的政策类型 - 汽车和家用,由两个不同的类别,汽车和家庭代表。

两者都有几个共同的数据位,因此两者都将从另一个名为Policy的类继承。 当用户登录应用程序时,他们可能有电机或家庭政策,因此应用程序需要显示通用信息以及Motor或Household独有的信息。 为了封装所有这些,我有一个具有Motor成员和Household成员的响应对象,如下所示:

public class Response
{
    ...
    private MotorPolicy                 _motorPolicy;
    private HouseholdPolicy             _householdPolicy;
    ....
}

以下代码应证明:

if (response.PolicyType == Enumerations.PolicyType.Motor) 
{
    lblDescription.Text = response.MotorPolicy.Description;
    lblReg.Text = response.MotorPolicy.Reg;
}
else
{
    lblDescription.Text = response.HouseholdPolicy.Description;
    lblContents.Text = response.HouseholdPolicy.Contents;
}

MotorPolicy没有Contents属性,而HouseholdPolicy没有Reg属性。

但我真的想干脆做到:

if (response.PolicyType == Enumerations.PolicyType.Motor) 
{
    lblDescription.Text = response.Policy.Description;
    ...
}

我试过使用泛型,找不到合适的解决方案。

您的响应只需要一个Policy类型,然后您可以将MotorPolicy或HouseholdPolicy类型存储到其中。

然后您的响应只需要检查数据类型

if (response.Policy is MotorPolicy) ....

或者,有一个抽象方法或属性从Policy类型的抽象方法返回数据,该方法完全由子类提供,并将reg数据或内容数据作为apporpriate返回。

每个政策后代(现在你有两个,未来可能有更多,对吗?)应该有自己的UI控件,“知道”如何处理政策信息。 同样的方法可以用于其他事情,例如策略对象的“控制器”等。

然后可以使响应变得通用:

public class Response<T> where T: Policy {
    ...
    private T _policy;
    ....
}

或者,你可以有一个更通用的方法,它使用反射来显示信息,但是它们的外观和可用性通常不那么“性感”(想想VS设计师中的Property Grid)。

public interface IPolicy
{
    string Description { get; }
    string Reg { get; }
    string Contents { get; }
}

public class MotorPolicy : IPolicy
{
    public string Description
    {
        get { return ...; }
    }

    public string Reg
    {
        get { return ...; }
    }

    public string Contents
    {
        get { return String.Empty; }
    }
}

public class HousholdPolicy : IPolicy
{
    public string Description
    {
        get { return ...; }
    }

    public string Reg
    {
        get { return String.Empty; }
    }

    public string Contents
    {
        get { return ...; }
    }
}

public class Response
{
    ...
    private IPolicy             _policy;
    ....
}

现在您不需要枚举来显示您已实现的类型,您可以这么说

lblDescription.Text = response.Policy.Description;
lblReg.Text = response.Policy.Reg;
lblContents.Text = response.Policy.Contents;

编辑:替代解决方案

public interface IPolicy
{
    string Description { get; }
}

public interface IHasReg
{
    string Reg { get; }
}

public interface IHasContents
{
    string Contents { get; }
}

public class MotorPolicy : IPolicy, IHasReg
{
    public string Description
    {
        get { return ...; }
    }

    public string Reg
    {
        get { return ...; }
    }
}

public class HouseholdPolicy : IPolicy, IHasContents
{
    public string Description
    {
        get { return ...; }
    }

    public string Contents
    {
        get { return ...; }
    }
}

public class Response
{
    ...
    private IPolicy             _policy;
    ....
}

这会在调用函数中留下更多代码

lblDescription.Text = response.Policy.Description;
IHasReg hasReg = response.Policy as IHasReg;
if (hasReg != null) lblReg.Text = hasReg.Reg;
IHasContents hasContents = response.Policy as IHasContents;
if (hasContents != null) lblContents.Text = hasContents.Contents;

但是比其他选项具有更大的可扩展性,并且符合您在实现中避免功能的愿望,这是没有意义的。

一种选择是向Policy添加一个成员,该成员合成所有派生类的相关属性以提供摘要:

 public abstract class Policy {
     public string Description { get; set; }
     public abstract string Summary { get; }
 }

 public class MotorPolicy: Policy {
     public override string Summary {
         get { return this.Description + "\r\n" + this.Reg; }
     }
 }

 public class HouseholdPolicy: Policy {
     public override string Summary {
         get { return this.Description + "\r\n" + this.Contents; }
     }
 }

这集中了逻辑并使用户界面代码变得简单:

 label.Description.Text = response.Policy.Summary;

该基本实现牺牲了单独格式化子部分的能力。 您可以通过将摘要公开为字符串集合来克服这一点:

public abstract IEnumerable<string> SummarySections { get; }

如果要以完全不同的方式显示派生类的详细信息,则必须在用户界面层中包含条件逻辑(例如,您可以在表中列出家庭策略的内容,但显示扫描的图像汽车政策的注册)。

使用模板模式:

使用虚拟抽象get方法创建一个名为Policy的基类,以确定策略的描述。

public abstract class Policy
{ 
    protected virtual string GetDescription()
    {
         return string.Empty()    
    }

    public string Description 
    { 
        get 
        {
           return GetDescription();
        } 
    }
}

public MotorPolicy : Policy
{
    public override string GetDescription()
    {
       return ..... ////specific description implementation for MotorPolicy
    }
}

public HouseHoldPolicy : Policy
{
    public override string GetDescription()
    {
       return ..... ////specific description implementation for HouseholdPolicy
    }
}


public class Response        
{        
    ...        
    private MotorPolicy                 _motorPolicy;        
    private HouseholdPolicy             _householdPolicy; 
    private PolicyType                  _policyType;       
    ....        

    public Policy Policy
    {
        get
        {
           if (_policyType== PolicyType.Motor) 
           {
              return _motorPolicy;
           } 
           if (_policyType== PolicyType.Household) 
           {
              return _householdPolicy;
           } 

           return null;
        }
    }        
}    

客户代码:

if (response.Policy != null)        
{       
    lblDescription.Text = response.Policy.Description;       
    ...       
}    

让MotorPolicy和HouseholdPolicy派生自Policy并从基础覆盖抽象get方法并创建它的特定实现。

在Response类中,只需获取描述。

定义Policy接口并在两个策略类中实现它

Interface IPolicy{
    int Reg {get;set;};
    string Contents {get;set;};
}

MotorPolicy : Policy,IPolicy {

 string IPolicy.Contents 
     {get;set;};


 int IPolicy.Reg 
     {get;set;};

}

HouseholdPolicy : Policy , IPolicy {
 string IPolicy.Contents 
     {get;set;};


 int IPolicy.Reg 
     {get;set;};
}

最简单的解决方案是实现具有description属性和“contents”属性的接口,然后在您的motor策略类中创建一个返回“reg”的虚拟“contents”属性。

您的回复是否可以包含MotorPolicy或HouseholdPolicy,还是可以包含其中一个?

如果您正在处理其中一个,那么创建一个基类型,两个类都继承定义公共属性。 输出公共属性时,只需将Policy作为基类型转换并使用它。

我的直接想法是:

public abstract class Response
{
  public abstract Policy Policy {get;}//can be used for stuff for dealing with all policies.
  public static Response GetResponse(Policy policy)
  {//factory method
    if(policy is MotorPolicy)
      return new MotorResponse((MotorPolicy)policy);
    if(policy is HouseholdPolicy)
      return new HouseholdResponse((HouseholdPolicy)policy);
    throw new ArgumentException("Unexpected policy type");
  }
}
public class MotorResponse : Response
{
  private readonly MotorPolicy _motorPolicy;
  public MotorResponse(MotorPolicy policy)
  {
    _motorPolicy = policy;
  }
  protected override Policy Policy
  {
    get { return _motorPolicy; }
  }
  // motor specific stuff
}
public class HouseholdResponse : Response
{
  private readonly HouseholdPolicy _householdPolicy;
  public HouseholdResponse(HouseholdPolicy policy)
  {
    _householdPolicy = policy;
  }
  protected override Policy Policy
  {
    get { return _householdPolicy; }
  }
  // household specific stuff
}

我会尝试这样的事情:

  public class Response
  {
     public Policy SelectedPolicy {get;set;}

     //I don't think you need these, but hard to 
     //say without seeing the rest of the code
     ...
     private MotorPolicy                 _motorPolicy;
     private HouseholdPolicy             _householdPolicy;
     ....
  }

然后

lblDescription.Text = response.SelectedPolicy.Description;

if (SelectedPolicy is MotorPolicy)
    lblReg.Text = ((MotorPolicy)response.SelectedPolicy).Reg;

else if (SelectedPolicy is HouseholdPolicy)
    lblContents.Text = ((HouseholdPolicy)response.SelectedPolicy).Contents;

我不会将Reg和Contents都放在基类或接口中。 如果我做的是继承的目的,如果所有类看起来都一样? 我得到的唯一好处就是类型,在这种情况下,这不会让我受益匪浅。

也许我不明白这个问题,但我只会使用继承

将政策定义为

public class Policy {public string Description {get; set;} public string Details {get; 组;}

}

public class MotorPolicy:Policy 
{
    public void SetReg(string reg)
    {
        base.Details = reg;
    }
}

public class HousePolicy:Policy 
{
    public void SetContents(string contents)
    {
        base.Details = contents;
    }
}

并打电话给

    private void Form1_Load(object sender, EventArgs e)
    {
        MotorPolicy mp = new MotorPolicy();
        mp.Description = "Motor";
        SetForm(mp);       
    }

    private void SetForm(Policy p)
    {
        lblDescription.Text = p.Description;
        lblDetail.Text = p.Details;

        //then if you still need specifics 
        if (p.GetType() == typeof(MotorPolicy))
        {
            MotorPolicy mp = p as MotorPolicy;
            //continue assigning mp
        }
        else if (p.GetType() == typeof(HousePolicy))
        {
            HousePolicy hp = p as HousePolicy;
            //continue assigning Hp
        }
    }

注意我将reg / contents作为字段详细信息,因为它们都是字符串类型。 如果一个是int vs string,那么它们必须分开完成。

你的是“重构多态性条件”的独特例子[福勒]。

然后你的方法应该接受正确的对象,并执行如下操作:

public void Update(IPolicy policy)
{
        lblDescription.Text = policy.Description;
        lblReg.Text = .Reg;

}

好吧,我不喜欢抽象类,所以我选择了一个Policy接口

public interface IPolicy
{
    string Description { get; set;}
    void Display();
}

然后我们继承它来创建MotorPolicy

public class MotorPolicy : IPolicy
{
    public string Description { get; set; }
    public string Reg { get; set; }

    public void Display()
    {
        Console.WriteLine(string.Format("Description: {0}", Description));
        Console.WriteLine(string.Format("Reg: {0}", Reg));
    }
}

然后,为了响应,我将策略更改为一个列表,您可以同时拥有两个或两个。 现在我们已经将显示数据的处理卸载到特定的策略本身。

public class Response
{
    public List<IPolicy> Policies { get; set; }

    public void Display()
    {
        Policies.ForEach(p => p.Display());
    }

    public void Display(Type t)
    {
        var policy = (from p in Policies
                      where p.GetType() == t
                      select p).FirstOrDefault();
        policy.Display();
    }
}

这可以很容易地改为不使用List,我们可以摆脱重载的显示。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM