C #: множественное наследование с неабстрактными вычисляемыми свойствами - PullRequest
5 голосов
/ 04 марта 2011

Я создаю серию классов Interfaces / Abstract, которые содержат базовые свойства, и я хотел бы иметь вычисляемые свойства и множественное наследование.

public abstract class /interface Modifiable
{
   public DateTime ModifiedDate {get; set;}

   public boo ModifiedToday
   {
     get { return DateTime.Now.AddDays(-1).CompareTo(ModifiedDate) >= 0; }
   } 

   public bool ModifiedInLastWeek
   {
     get { return DateTime.Now.AddDays(-7).CompareTo(ModifiedDate) >= 0; }
   }
}

public abstract class /interface Deletable
{
   public DateTime DeletionDate {get; set;}    

   public bool Deleted
   {
     get { return DeletionDate != default(DateTime) }
   }
}

Тогда у меня есть класс, который наследует от этих двух интерфейсов / абстрактных классов.

public class Something : Modifiable, Deletable 
{
  //
}

Но класс не может наследоваться от двух абстрактных классов. Поэтому мне нужно использовать интерфейсы, но с интерфейсами я не могу иметь тела методов. Затем я должен определить одни и те же точные функции для нескольких классов, чтобы реализовать эти простые свойства bool с использованием интерфейсов.

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

Существует ли шаблон проектирования, который имитирует абстрактный класс, разрешая тела функций, но допускает множественные наследники, такие как интерфейс?

Ответы [ 7 ]

1 голос
/ 04 марта 2011

Да, есть несколько методов, на самом деле.Несколько соображений:

  • Используйте пустой интерфейс для Deletable, Modifiable и т. Д. (Так называемые маркерные интерфейсы), затем создайте методы расширения для них.Это не так расширяемо, как множественное наследование, но оно проходит долгий путь.
  • Используйте универсальность, возможно, с такими же интерфейсами тегов для создания зависимостей.Таким образом, вы можете иметь базовый класс со всеми методами как Modifiable и Deletable, включая абстрактные методы и реализацию переопределения в производных классах
  • Использование аспектно-ориентированного программирования для получения одинаковых результатов
  • Почтито же самое, но сделайте это самостоятельно с помощью Castle или подобной библиотеки, возможно, с помощью атрибутов.

Очевидно, что ни одно из перечисленных выше не обладает всеми преимуществами множественного наследования.Если вы хотите множественное наследование в .NET, вы можете использовать C ++. NET или Eiffel.NET.

1 голос
/ 04 марта 2011

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

interface IDrivable {
  void Drive();
}

interface IFlyable {
  void Fly();
}

class Car : IDrivable {
  public void Drive() { /* Implementation */ }
}

class Plane : IFlyable {
  public void Fly() { /* Implementation */ }
}

class MyClass : IDrivable, IFlyable {
  private IDrivable _car = new Car();
  private IFlyable _plane = new Plane();

  public void Drive() { _car.Drive(); }
  public void Fly() { _plane.Fly(); }
}
1 голос
/ 04 марта 2011

Это не множественное наследование, а то, что приходит на ум, это методы расширения.

public interface IModifiable
{
    DateTime ModifiedDate {get; set;}
}

public static class ModifiableExtensions
{
   public bool ModifiedToday(this IModifiable m)
   {
      return DateTime.Now.AddDays(-1).CompareTo(m.ModifiedDate) >= 0;
   } 

   public bool ModifiedInLastWeek(this IModifiable m)
   {
     return DateTime.Now.AddDays(-7).CompareTo(m.ModifiedDate) >= 0; 
   }

}

Это дает "чувство" вспомогательных методов, которые запекаются в тип, но они, как оказалось, объявлены в другом месте. Возьми этот класс:

public class MyModifiable :IModifiable
{
     public ModifiedDate {get; set;}
}

И вы можете сделать это:

MyModifiable m = new MyModifiable;

m.ModifiedDate = DateTime.Now;

bool isToday = m.ModifiedToday();
1 голос
/ 04 марта 2011

Нет.C # не имеет механизма для реализации множественного наследования таким способом.

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

Рассмотримдругой дизайн, возможно, с использованием композиции для повторного использования классов, которые вы хотите использовать для множественного наследования.

0 голосов
/ 04 марта 2011

Я бы, вероятно, использовал делегирование для достижения этой цели.Создайте Modifiable и Deletable как интерфейсы, затем создайте их реализацию.Дайте Something экземплярам класса этих реализаций.Вот пример для Deletable:

public interface Deletable
{
  DateTime DeletionDate{get;set;}
  bool Deleted{get;}
}

public class DeletableImpl : Deletable
{
  public DateTime DeletionDate{get; set;}
  public bool Deleted{get {return DeletionDate != default(DateTime);}}
}
// Do the same thing with Modifiable and ModifiableImpl

public class Something : Deletable, Modifiable
{
  private Deletable _deletable = new DeletableImpl();
  private Modifiable _modifiable = new ModifiableImpl();
  public DateTime DeletionDate
  {
    get{return _deletable.DeletionDate;}
    set{_deletable.DeletionDate = value;}
  }
  public bool Deleted{get{return _deletable.Deleted;}}
  public DateTime ModifiedDate {
    // and so on as above
}
0 голосов
/ 04 марта 2011

Модифицируемые и удаляемые ИМО должны быть интерфейсами, а не базовыми классами. Базовый класс определяет, что такое тип, тогда как интерфейс описывает, что делает тип.

Что касается реализации кода, вы всегда можете использовать методы расширения:

public interface IModifiable
{
   public DateTime ModifiedDate {get; set;}
}

public interface IDeletable
{
   public DateTime DeletionDate {get; set;}    
}


public static class SomeExtentions
{
    public static bool IsModifiedToday(this IModifiable modifiable)
    {
        return DateTime.Now.AddDays(-1).CompareTo(modifiable.ModifiedDate) >= 0;
    } 

    public static bool IsModifiedInLastWeek(this IModifiable modifiable)
    {
        return DateTime.Now.AddDays(-7).CompareTo(modifiable.ModifiedDate) >= 0;
    }   
    public static bool IsDeleted(this IDeletable deletable)
    {
        return deletable.DeletionDate != default(DateTime);
    }
}
0 голосов
/ 04 марта 2011

Извините, множественное наследование невозможно в C #, и это для вас облом. Ваш выбор:

  1. Либо связать наследование базового класса в стиле MyClass: MyBaseClass: EvenBasierClass
  2. Или наследовать от нескольких интерфейсов. И реализовать все методы всех интерфейсов.

Это не красиво, но вы также можете контролировать доступность свойств или возвращать значения внутри ваших классов, проверяя тип экземпляра.

...