Скажем, я определяю класс реализации браузера для своего приложения:
class InternetExplorerBrowser : IBrowser {
private readonly string executablePath = @"C:\Program Files\...\...\ie.exe";
...code that uses executablePath
}
На первый взгляд это может показаться хорошей идеей, так как данные executablePath
находятся рядом с кодом, который будет использовать его.
Проблема возникает, когда я пытаюсь запустить это же приложение на моем другом компьютере, на котором есть ОС на внешнем языке: executablePath
будет иметь другое значение.
Я мог бы решить это через класс Singleton AppSettings (или один из его эквивалентов), но тогда никто не знает, что мой класс на самом деле зависит от этого класса AppSettings (что противоречит идеям DI). Это может также затруднить тестирование Unit-Testing.
Я мог бы решить обе проблемы, передав executablePath
через конструктор:
class InternetExplorerBrowser : IBrowser {
private readonly string executablePath;
public InternetExplorerBrowser(string executablePath) {
this.executablePath = executablePath;
}
}
но это вызовет проблемы в моем Composition Root
(метод запуска, который сделает все необходимые проводки классов), так как тогда этот метод должен знать, как подключаться к ним, и знать все эти данные небольших настроек:
class CompositionRoot {
public void Run() {
ClassA classA = new ClassA();
string ieSetting1 = "C:\asdapo\poka\poskdaposka.exe";
string ieSetting2 = "IE_SETTING_ABC";
string ieSetting3 = "lol.bmp";
ClassB classB = new ClassB(ieSetting1);
ClassC classC = new ClassC(B, ieSetting2, ieSetting3);
...
}
}
который легко превратится в большой беспорядок.
Я мог бы обратиться к этой проблеме, вместо этого передав интерфейс формы
interface IAppSettings {
object GetData(string name);
}
для всех классов, для которых требуются какие-то настройки. Затем я мог либо реализовать это, либо как обычный класс со всеми встроенными в него параметрами, либо классом, который считывает данные из файла XML, что-то вроде строк. Если это необходимо, должен ли я иметь общий класс класса AppSettings для всей системы или иметь класс AppSettings, связанный с каждым классом, который может понадобиться? Это, безусловно, похоже на перебор. Кроме того, все настройки приложения в одном и том же месте облегчают просмотр и видят, какие могут быть все изменения, которые мне нужно сделать, когда tryign перемещает программу на разные платформы.
Что может быть лучшим способом приблизиться к этой общей ситуации?
Изменить:
А как насчет использования IAppSettings
со всеми его настройками, жестко закодированными в нем?
interface IAppSettings {
string IE_ExecutablePath { get; }
int IE_Version { get; }
...
}
Это позволит обеспечить безопасность во время компиляции. Если бы я увидел, что классы интерфейса/конкретного класса слишком сильно растут, я мог бы создать другие меньшие интерфейсы формы IMyClassXAppSettings
. Будет ли это слишком тяжелым бременем для медсёмочных проектов?
Я также читаю об АОП и его преимуществах, связанных с сквозными проблемами (я думаю, это один). Не могли бы также предложить решения этой проблемы? Возможно, помечают такие переменные:
class InternetExplorerBrowser : IBrowser {
[AppSetting] string executablePath;
[AppSetting] int ieVersion;
...code that uses executablePath
}
Затем, при компиляции проекта, у нас также была бы безопасность времени компиляции (когда компилятор проверял, что мы действительно реализовали код, который будет переплетаться с данными. Это, конечно же, связывает наш API с этим конкретным аспектом.