簡體   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