Как расширить иерархию объектов для хранения дополнительных данных? - PullRequest
2 голосов
/ 27 июля 2010

Я работаю в кодовой базе C #, которая имеет иерархию классов:

class Animal { Animal prey; }
class Mammal : Animal { Mammal[] livesAmicablyWith; }
class Lion : Mammal { }

Простите за глупый пример.

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

class Animal { Animal prey; string moreAnimalData; }
class Mammal : Animal { Mammal[] livesAmicablyWith; string moreMammalData; }
class Lion : Mammal { string moreLionData; }

Однако я хочу избегать добавления членов в эту существующую иерархию, поскольку в лучшем случае они будут потрачены впустую, а в худшем - отвлекаться от ошибок.

Кроме того, мне нужны все оригинальные функции, чтобы продолжить работу! Вот о чем я думал:

class AnimalExtended : Animal {  }
class MammalExtended : Mammal {  
    public void UseLivesAmicablyWith()
    {
        foreach(Mammal m in livesAmicablyWith)
        {
            if(!(m is MammalExtended)
                throw new Exception();

            // use the MammalExtended
        }
    }
}
class LionExtended : Lion {  }

Есть предложения?

Ответы [ 4 ]

1 голос
/ 27 июля 2010

По сути, вы пытаетесь обработать множественное наследование, что, конечно, вы не можете сделать в C # (об этом см. Множество Q в Stackoverflow).

Ваши опции включают в себя: -

Перейти к интерфейсам : IAnimal, IMammal, ILion и прекратить использование классов при обращении к этим элементам. Теперь вы можете создать уродливый большой комбо-класс, но ссылаться на него можно только с помощью IAnimal или IAnimalExtended, чтобы были видны только соответствующие свойства. Еще лучше использовать интерфейсы, которые группируют различные логические функции; возможно ISocial вместо IAnimalExtended, где ISocial определяет, как существа взаимодействуют друг с другом.

Использование композиции вместо наследования : LionExtended предоставит свойства для Feeding и SocialNature, которые реализованы не в некотором базовом классе Animal, а в меньших классах, которые имеют дело только с одной проблемой .

Делать оба : использовать интерфейсы и отдавать предпочтение композиции перед наследованием.

0 голосов
/ 27 июля 2010

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

0 голосов
/ 27 июля 2010

Я думаю, что выбранный вами подход обоснован и будет работать. Я бы попытался выполнить проверку типа (например, млекопитающие, добавленные в LifeAmicblywith) во время добавления значений (при условии, что это как-то инкапсулировано), а не во время их использования. Это значительно упростит отлов ошибок.

0 голосов
/ 27 июля 2010

Полагаю, это зависит от того, насколько «стандартными» будут дополнительные данные. Вы можете просто использовать больше полиморфизма для достижения результата:

interface IExtendedData
{
    string GetMoreData<T>();
}

class ExtendedAnimal: Animal, IExtendedData
{
    public virtual string GetMoreData<T>()
    { 
        if (typeof(T) == typeof(Animal))
            return "Extra animal data";

        return String.Empty;
    }
}

class ExtendedMammal: Mammal, IExtendedData
{
    public override string GetMoreData<T>()
    { 
        if (typeof(T) == typeof(Mammal))
            return "Extra mammal data";

        return base.GetMoreData<Animal>();
    }
}

class ExtendedLion: Lion, IExtendedData
{
    public override string GetMoreData<T>()
    { 
        if (typeof(T) == typeof(Lion))
            return "Extra lion data";

        return base.GetMoreData<Mammal>();
    }
}

При использовании вы можете динамически приводить к IExtendedData для независимого получения дополнительных данных:

var mammal = getLion(); // Returns a lion...possibly an ExtendedLion, but possibly not
var extended = mammal as IExtendedData;
if (extended != null)
{
    string mammalData = extended.GetMoreData<Mammal>();
    string lionData = extended.GetMoreData<Lion>();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...