Наследование класса C # - PullRequest
       11

Наследование класса C #

7 голосов
/ 05 октября 2010

Я работаю со страховкой и имею два разных типа полиса - автомобильный и бытовой, представленный двумя разными классами, автомобильный и бытовой.

Оба имеют несколько общих бит данных, поэтому оба наследуют от другого класса, называемого Policy.Когда пользователь входит в приложение, у него может быть политика в отношении двигателя или домашнего хозяйства, поэтому приложение должно отображать общую информацию и информацию, уникальную для Motor или Household.Чтобы инкапсулировать все это, у меня есть объект ответа, в котором есть и член Motor, и член домохозяйства, как показано ниже:

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;
    ...
}

Я пробовал использовать дженерики, не могнайти правильное решение.

Ответы [ 13 ]

5 голосов
/ 05 октября 2010

Каждый потомок Политики (теперь у вас есть два, у вас может быть больше в будущем, правильно?) Должен иметь свои собственные элементы управления пользовательским интерфейсом, которые «знают», как обращаться с информацией о политике. Тот же подход можно использовать для других целей, таких как «контроллер» для объектов политики и т. Д.

Ответ можно сделать общим:

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

В качестве альтернативы, у вас может быть более общий подход, который использует отражение для отображения информации, но они обычно менее "сексуальны" по внешнему виду и удобству использования (подумайте о Grid Property в конструкторе VS).

5 голосов
/ 05 октября 2010

Для вашего ответа нужен только тип политики, вы можете сохранить в нем тип MotorPolicy или HouseholdPolicy.

Тогда ваш ответ просто должен проверить тип данных

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

В качестве альтернативы есть абстрактный метод или свойство, возвращающее данные из абстрактного метода в типе Policy, который полностью дополняется дочерними классами и возвращает данные reg или данные содержимого как соответствующие.

1 голос
/ 05 октября 2010

Используйте шаблон шаблона:

Создайте базовый класс с именем Policy с виртуальным абстрактным методом get для определения описания политики.

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 просто получите описание.

1 голос
/ 05 октября 2010

Один из вариантов - добавить в 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; }

Если вы хотите отобразить детали производных классов принципиально различными способами, вам придется принять условную логику в пользователеинтерфейсный уровень (например, вы можете перечислить содержимое политики домохозяйства в таблице, но показать отсканированное изображение для регистрации политики автомобиля).

1 голос
/ 05 октября 2010
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;

, но значительно более расширяемо, чем другие представленные опции, и соответствует вашему желанию избежать функциональности в реализации, которая не имеет смысла.

0 голосов
/ 05 октября 2010

Ну, мне не нравятся абстрактные классы, поэтому я выбрал интерфейс для 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();
    }
}

Это можно легко изменить, чтобы не использовать Список, и мы можем избавиться от перегруженного дисплея.

0 голосов
/ 05 октября 2010

Ваш уникальный пример «Рефакторинг состояния к полиморфизму» [Фаулер].

И тогда ваш метод должен принять правильный объект и сделать, как показано ниже:

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

}
0 голосов
/ 05 октября 2010

возможно я не понимаю вопроса, но я бы просто использовал наследование

определить политику как

Политика публичного класса { открытая строка Описание {get; задавать;} открытая строка 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 против строки, то они должны быть сделаны отдельно.

0 голосов
/ 05 октября 2010

Я бы попробовал что-то вроде этого:

  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 в базовый класс или интерфейс.Если я делаю, какова цель наследования, если все классы выглядят одинаково?Единственными преимуществами, которые я получу, были бы типы, и это не принесет мне особой пользы в этом случае.

0 голосов
/ 05 октября 2010

Моя непосредственная мысль - пойти на:

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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...