locked
Enum и наследование RRS feed

  • Вопрос

  • Я прекрасно понимаю, что наследовать enum"ы нельзя, просто именно с их наследованием задача решилась бы элегантно.

    Есть интерфейс, определяющий методы для запросов к различным сервисам распознавания текста (OCR.space, Microsoft Vision, Google Vision...). Один из методов получает как параметр предполагаемый язык. Для этого я создал enum, который используется как тип этого параметра и уже в конкретной реализации я его "преобразую" в необходимую строку. Проблема в том, что эти сервисы имеют похожий, но всё же отличающийся список поддерживаемых языков. Например, сервис №1 поддерживает язык А, но не поддерживает язык Б, сервис №2 - наоборот, а сервис №3 - поддерживает (или не поддерживает) оба. Здесь бы в идеале было бы использовать "базовый" класс enum"а как параметр и передавать уже конкретную реализацию. Но они не поддерживают наследование. Как элегантно решить эту проблему?

    Спасибо.

    11 апреля 2017 г. 22:16

Ответы

  • Еще раз, тип объекта это уже информация о том какой язык нужно распознавать. Если у вас есть возможность создать объект нужного типа до вызова метода, то спокойно его создаете и передаете в метод. Если такой возможности нет, то в метод передаете строку или enum, или что угодно. А потом на основе этой информации создаете объект распознователь. Сам enum или строка после этого вам уже не нужны.
    Ну а по иерархии наследования, в самый базовый класс надо выносить только то, что действительно никогда не поменяется, ну и ми можно внести еще один уровень потомков расширяющих базовый класс (например, для латинской группы, для письма на основе иероглифов и т.д.). Но это надо вдумчиво смотреть. Не зная вашей специфики подсказать что-то конкретное тяжело.
    17 апреля 2017 г. 6:03
    Отвечающий

Все ответы

  • Добрый день.

    Отказаться от Enum и начать использоваться классы. Список значений сделайте константами.

    12 апреля 2017 г. 5:48
    Отвечающий
  • Добрый день.

    Отказаться от Enum и начать использоваться классы. Список значений сделайте константами.

    У меня были такие мысли. Но список констант как членов класса немного настораживает

    При этом не пойму, как правильно реализовать.

    Есть интерфейс:

    public interface IOCR { Task<OCRResult> GetTextAsync(string fileUrl, Language language); }

    Есть энум:

    public enum Language
    {
        Chinese_Simplified,
        Chinese_Traditional,
        Danish,
        Dutch,
        ....
    }

    есть конкретная реализация, в которой сопоставляю этот enum с необходимым строковым значением:

            protected string GetLanguage(eLanguage eLanguage)
            {
                string language = "unk";
    
                switch (eLanguage)
                {
                    case eLanguage.Danish:
                        language = "da";
                        break;
                    case eLanguage.Dutch:
                        language = "nl";
                        break;
                    case eLanguage.English:
                        language = "en";
                        break;
                    case eLanguage.Finnish:
                        language = "fi";
                        break;
                    case eLanguage.French:
                        language = "fr";
                        break;
                    case eLanguage.Unknown:
                    default:
                        break;
                }
    
                return language;
            }
    как с константами такое провернуть - не знаю. При наследовании придётся добавлять новые константы и каким-то образом "смотреть", какая из них была выбрана...



    12 апреля 2017 г. 6:42
  • Про Enum:

    Ключевое слово enum используется для объявления перечисления — отдельного типа, который состоит из набора именованных констант, называемого списком перечислителей.

    Это вот от сюда. Т.е. enum это не более чем синтаксический сахар для класса с набором констант.

    По поводу вашей задачи. У вас же кто-то перед вызовом метода определяет язык? Кто ему мешает вместо языка определить сразу класс используемый для распознования и передать его?

    12 апреля 2017 г. 7:35
    Отвечающий
  • По поводу вашей задачи. У вас же кто-то перед вызовом метода определяет язык? Кто ему мешает вместо языка определить сразу класс используемый для распознования и передать его?


    потому что должна быть абстракция, т.е. клиент ничего не знает про конкретный класс и работает только с интерфейсом IOCR
    12 апреля 2017 г. 7:38
  • И в чем проблема? У вас сейчас метод интерфейса принимает язык, ну ок, спрячьте в этом методе фабрику, которая на основе языка будет создавать объект класса предназначенного для обработки такого языка.
    12 апреля 2017 г. 8:30
    Отвечающий
  • И в чем проблема? У вас сейчас метод интерфейса принимает язык, ну ок, спрячьте в этом методе фабрику, которая на основе языка будет создавать объект класса предназначенного для обработки такого языка.

    Так часть языков "общие" для более чем одной реализации.
    12 апреля 2017 г. 9:05
  • По поводу вашей задачи. У вас же кто-то перед вызовом метода определяет язык? Кто ему мешает вместо языка определить сразу класс используемый для распознования и передать его?

     Видимо у топикстартера должен быть не "кто-то" а что -то могущее распознать языки.

    Фоновое изображение

    12 апреля 2017 г. 9:30
  • Так часть языков "общие" для более чем одной реализации.
    Вам в любом случае надо будет иметь преобразование языка в класс или метод для распознования. Причем отношение у вас может быть: несколько языков к одному классу, один язык к одному классу. Вот и напишите логику которая получив язык создает экземпляр нужного вам класса. Самый простой вариант создать Dictionry, где ключем будет язык, а значением тип (класс), ну и фабрику напишите, которая получив язык выбирает класс и создает его экземпляр.
    13 апреля 2017 г. 6:37
    Отвечающий
  • Добрый день.

    Отказаться от Enum и начать использоваться классы. Список значений сделайте константами.

    Константы также нельзя наследовать, сделав их virtual. Думаю сделать их обычными свойствами + отдельное свойство, которое хранит название выбранного свойства. Это правильный подход или через одно место?

    Вылазит ещё одна сложность - в базовом классе я задаю свойства, общие для всех сервисов. В дочернем переопределяю их значения + добавляю новые. Вроде всё работает. Но потом добавляется ещё один сервис, который не содержит одно (или более) свойство, которое есть в базовом классе. И принцип того, что при добавлении дочернего класса нужно колупать главный, нарушается. Что-то не так в архитектуре. Как её всё же правильно сделать? Просто передавать string как значение и потом проверять действительное ли это значение?

    14 апреля 2017 г. 18:46
  • Еще раз, тип объекта это уже информация о том какой язык нужно распознавать. Если у вас есть возможность создать объект нужного типа до вызова метода, то спокойно его создаете и передаете в метод. Если такой возможности нет, то в метод передаете строку или enum, или что угодно. А потом на основе этой информации создаете объект распознователь. Сам enum или строка после этого вам уже не нужны.
    Ну а по иерархии наследования, в самый базовый класс надо выносить только то, что действительно никогда не поменяется, ну и ми можно внести еще один уровень потомков расширяющих базовый класс (например, для латинской группы, для письма на основе иероглифов и т.д.). Но это надо вдумчиво смотреть. Не зная вашей специфики подсказать что-то конкретное тяжело.
    17 апреля 2017 г. 6:03
    Отвечающий