Nano Hash - криптовалюты, майнинг, программирование

Фабрика простых классов, производных от общих специализаций

У меня есть общий класс С# B<T>. Также у меня есть набор производных классов Di : B<Ti>. Все эти классы всегда создаются с одним и тем же набором параметров. Таким образом, это приводит к спагетти-коду:

if (typeof(T) == typeof(A1)) {work with D1}
else if (typeof(T) == typeof(A2)) {work with D2}
...

Очевидно, я хочу реорганизовать код так, чтобы он выглядел так:

var dInst = GiveMeD<T>();
work with Di

Как я могу реализовать функцию GiveMeD<T>()?

ОБНОВЛЕНИЕ:

work with Di -> приведение к базовому классу B<T> и работа с его интерфейсом. Основная проблема здесь - каждый блок кода отличается вызовом конструктора производного класса.


  • Отличается ли работа с D1 от работы с D2 и так далее? 14.06.2016
  • public static T GiveMeD‹T›(){ //здесь код } Код здесь будет иметь список объектов, вы можете написать запрос LINQ, подобный этому: var objs=List.Where(p=›p.GetType( )== Т). 14.06.2016
  • Я бы сказал не Where(), а FirstOrDefault()... 14.06.2016

Ответы:


1

Если вы хотите эффективно реорганизовать код таким образом, вы должны принять во внимание, что «работа с D1» и «работа с D2» должны быть одинаковыми, и должно различаться только поведение; то есть D1 и D2 должны иметь общий «интерфейс» (B<T>), и вы должны использовать только этот «интерфейс», иначе вы снова начнете использовать спагетти-код повсюду и уродливые приведения.

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

public static B<T> CreateD<T>()
{
    if (T is A1) return ... //here you can create a new instance of D1 or return a cached one, etc.
    else if (T is A2) return ...
}

Вот красивый шаблон, который я люблю использовать, когда потребителю не нужно ничего знать о D1, D2 и т. д., а нужно знать только о B<T>:

public class B<T>
{
    public B<T> CreateD<T>()
    {
        if (T is A1) return ... //here you can create a new instance of D1 or return a cached one, etc.
        else if (T is A2) return ...
        ...
    }

    private B() { } //note constructor is private, consumer can't create a B<T>

    private class D1: B<A1> { ... } //private nested types, not visible outside B<T>.
    private class D2: B<A2> { ... }
}

Теперь у вас есть абсолютный контроль над тем, сколько Di может быть реализовано, вы предоставляете один единственный универсальный B<T> и гарантируете, что всегда возвращаете правильно специализированный тип, фактически не заставляя потребителя что-либо знать об этом.

14.06.2016
  • У меня есть одно сомнение по поводу такого подхода: должен ли базовый класс знать о классах, производных от него? Я не верю. 14.06.2016
  • @ user2123007 И это не так. Тот факт, что производные классы являются частными вложенными классами в базовом классе, является просто удобным шаблоном для сокрытия деталей реализации от потребителя, но это все. Попробуйте найти хоть одну часть информации, которую B<T> имеет о D1 или D2, которой не было бы, если бы производные классы не были вложенными. 15.06.2016
  • @ user2123007 Шаблон private, вложенный в базовый класс, является решением для очень специфических сценариев. Как я уже сказал, он охватывает особые потребности, которые, безусловно, не являются общим случаем использования наследования. Очень вероятно, что в вашем конкретном сценарии этот шаблон не лучший подход, и обычного фабричного метода более чем достаточно. 15.06.2016
  • @ user2123007 Отличным примером использования этого шаблона является этот простой неизменяемый класс стека 15.06.2016
  • Новые материалы

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

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

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

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..