Как реализовать всеобъемлющий интерфейс для разных типов классов - PullRequest
1 голос
/ 05 апреля 2019

Я пытаюсь реализовать интерфейс с некоторыми базовыми функциями для изменения настроек BIOS от нескольких поставщиков компьютеров.

Пока у меня есть следующее:

public interface IBiosConfigurator
{
    bool IsBiosPasswordSet();

    bool ValidateBiosPassword(string password);

    bool SetBiosPassword(string currentPassword, string newPassword);

    T GetSetting<T>(string settingName, string password);

    T GetSetting<T>(string settingName, string propertyName, string password);

    bool SetSetting<T>(string settingName, T value, string password);
}

Однако я быстро понял, что это не соответствует тому, что мне нужно:

  • Если что-то не получается, я понятия не имею, почему. Был ли это плохой пароль? Значение, которое вы пытаетесь установить, не разрешено? Имя настройки не существует?

  • У каждого производителя есть свой способ отображения ошибок: одни используют целые, другие используют, другие - нет общего типа.

  • Даже простые методы, такие как bool IsBiosPasswordSet(), могут потерпеть неудачу, и это не учитывается.

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

Но мне все еще нужно возвращать фактический код ошибки, который что-то сгенерировал, и хотя мне кажется, что это нормально для объявления метода:

BiosErrorCode GetSetting<T>(string settingName, string password, out T value)

Я не могу сказать то же самое для:

BiosErrorCode IsBiosPasswordSet(out bool passwordSet);

Но единственный другой способ решить эту проблему - это свойство BiosErrorCode LastErrorCode, которое позволило бы мне сохранять декларацию методов такой, какая она есть, но немного похоже на PInvokes ...

Итак, я думаю, у меня есть два вопроса:

  1. Кто-нибудь может придумать лучший способ сделать это?
  2. Если нет, то более уместно использование свойства out params или BiosErrorCode?

Ответы [ 4 ]

0 голосов
/ 05 апреля 2019

Вы должны выбросить исключение, если что-то пойдет не так.Концептуально Исключения живут с вашим Interfcae, и вы никогда не должны выбрасывать ничего, что не упомянуто в документации по интерфейсу.

Это оставляет один путь к проблемам открытым, который плохо отражен в Исключении.Для тех у вас должна быть реализация ведения журналов, где реализующий класс получает регистратор во время создания и отслеживает все технические детали, которые вам могут понадобиться позже.Обычно просто писать в консоль, так как это может быть легко перенаправлено.Существуют более интересные фреймворки для ведения журналов. Реализующий класс должен получить регистратор в качестве интерфейса, который имеет строгие гарантии.

В большинстве случаев это действительно сводится к вашей документации.

Вотпример:

public class PasswordExpection : Exception
{
    public PasswordExpection(string msg) : base(msg) { }
}

public class BiosExpection : Exception
{
    public BiosExpection(string msg, Exception inner) : base(msg, inner) { }
}

interface IBiosControl
{
    /// <summary>
    /// Checks if a password is set.
    /// </summary>
    /// <exception cref="PasswordExpection">if the concept of password does not apply</exception>
    /// <exception cref="BiosExpection">if there was an execution error</exception>
    /// <returns>Weather or not the password was set</returns>
    bool IsPasswordSet();
}

public class MyBios : IBiosControl
{
    private readonly Action<string> _logger;

    public MyBios(Action<string> logger)
    {
        _logger = logger;
    }

    public bool IsPasswordSet()
    {
        try
        {
            _logger("MyBios IsPasswordSet Connecting To Bios...");
            throw new NotImplementedException();
        }
        catch(Exception e)
        {
            throw new BiosExpection("Execution Error", e);
        }
    }
}
0 голосов
/ 05 апреля 2019

В принципе Solid класс или интерфейс не должны охватывать множество не связанных между собой предприятий в одном объекте.

0 голосов
/ 05 апреля 2019

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

0 голосов
/ 05 апреля 2019

Я бы сказал, что слово Bios является избыточным. ;) Еще о серьезной стороне: я бы сказал, что если что-то пойдет не так, вы выбрасываете пользовательское исключение. При нормальных обстоятельствах ваши реализации должны просто возвращать то, что вы ожидаете. Так что, если это не так, это действительно исключение, и для этого есть исключения.

Позволяет скрыть логику, специфичную для поставщика, для создания этих исключений для реализации, специфичной для поставщика.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...