2016-07-04 12 views
0

У меня есть дилемма дизайна класса: у меня есть общий базовый класс и несколько производных классов. База представляет собой класс CRTP, который обеспечивает общие функции, некоторые из которых требуют данных, относящихся к унаследованным классам. Поэтому базовый класс является абстрактным, а дочерние классы должны реализовывать определенные методы «поставщика». Например:C# класс дизайн - экземпляр независимой информации

public abstract class Base<T> where T : Base<T>, new() { 
    private static T reference = new T(); 

    public static int Foo => reference.GetFoo(); 

    public static string Bar => reference.GetBar(); 

    protected abstract int GetFoo(); 

    protected abstract string GetBar(); 

    // ... 
} 

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

public void ComputeSomething<T>() where T : Base<T>, new() { 
    int foo = Base<T>.Foo; 

    // ... 
} 

Или, если класс отрока: ChildClass.Foo

Это работает, но в целом решение чувствует себя «грязным», как я ненавижу помещайте каждый экземпляр с информацией о типе, а базовый класс должен содержать экземпляр reference (как подкласс может быть создан в базовом классе, он все еще немного изгибает мой мозг и, как правило, кажется плохой идеей). Я бы поместил информацию в кеш или фабрику или что-то еще, но я не контролирую все дочерние классы, поэтому система должна расширяться. Я посмотрел на использование атрибутов, но нет способа (я знаю), чтобы обеспечить соблюдение определенных атрибутов во время компиляции. На самом деле, мне кажется, что мне нужны статические интерфейсы или статические абстрактные элементы, но у C# их нет.

Так что мой вопрос: как эта проблема вообще решена?

+0

Можете ли вы изменить/реорганизовать код, который использует статические элементы, вместо этого использовать только абстрактные элементы?Как правило, в мире, в котором царит проверка/инверсия управления/зависимость, вы будете стремиться к тому, чтобы все элементы кода использовали нестатические элементы, чтобы они легко подменялись или издевались ... – Reddog

+0

И в отношении вашего утверждения «Как может быть подкласс созданный в своем базовом классе, по-прежнему немного изгибает мой мозг и, как правило, кажется плохой идеей »- Да! Вы правы, плохая идея. Вы ограничиваете себя в отношении зависимостей от строительства и так далее. – Reddog

+0

Да, конечно, я могу реорганизовать код, это скорее прототип. Во многих местах (как в примере) это приведет к чему-то вроде «нового T(). Foo', который просто не кажется правильным. Я начинаю думать, что мне нужен отдельный класс провайдера или что-то – Blue0500

ответ

0

Я начинаю думать, что мне нужен отдельный класс поставщика или что-то

Это ответ. Всякий раз, когда я попадаю в эти сложные типичные сценарии наследования, проблема в том, что я совмещаю классы по наследованию, а не по составу. Вот почему вы услышите принцип «favor composition over inheritance.»

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

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

Что я обнаружил, так это то, что наследование чаще всего работает, когда оно является результатом рефакторинга, возможно, способ реорганизовать дублирующий код (или остановить его до его начала). Когда я начну с него думать, что я собираюсь повторное использование кода, скорее всего, заканчивается слишком запутанным. Возможно, это потому, что мы все еще пишем классы и определяем, как они будут работать. Попытка построить иерархию заставляет нас предположить слишком много фронта, а затем разочаровывать отказаться от дизайна. Он работает лучше при рефакторинге в ретроспективе или когда мы рассматриваем возможность добавления новых классов, которые могут дублировать код.

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

+0

Спасибо! Это именно то, что мне нужно было услышать. Я думаю, что я просто слишком долго смотрел на код ... Сегодня я прочитал это, переместил некоторые функции, сделал некоторые интерфейсы и т. Д., И все это в значительной степени разобралось. В любом случае, спасибо! – Blue0500

+0

Отлично. Я снова и снова нарисовал себя в странных родовых углах наследования, так что это действительно помогло, когда кто-то объяснил мне альтернативу. –

 Смежные вопросы

  • Нет связанных вопросов^_^