Принцип открытости/закрытости
Пытаюсь понять принцип открытости/закрытости.
Размышляю над этим примером
Пример плохого кода:
public void addButton(string os)
{
var creator = new Creator();
if (os == "linux")
{
creator.createLinuxButton();
}
else if (os == " windows")
{
creator.createWindowsButton();
}
}
Очевидно что при добавлении других os придётся дописывать новые else if и нарушать принцип. Лучшим выходом будет паттерн абстрактная фабрика. Однако она не помогает избавиться от расширения через else if, а лишь переносит эту конструкцию в метод уровнем выше
//метод более высокого уровня вызывающий addButton
if (os == "linux")
{
var creator = new LinuxCreator();
}
else if (os == "windows")
{
var creator = new WindowsCreator();
}
addButton(creator);
В итоге при добавлении os опять придётся дописывать код в уже созданный метод и добавлять else if, принцип нарушен?
Ответы (1 шт):
Без лишних слов, починить это можно просто если унести код выбора из метода создания кнопки в точку сборки приложения.
Допустим, фабричный метод уже есть, и есть абстракция Creator и наследники WindowsCreator и LinuxCreator, и есть метод создания кнопки, перепишу его немного.
public Button CreateButton(string os)
{
Creator creator = os switch
{
"windows" => new WindowsCreator(),
"linux" => new LinuxCreator(),
_ => throw new PlatformNotSupportedException()
};
return creator.CreateButton();
}
Чтобы не нарушать OCP, достаточно унести это в единую точку компоновки приложения, например:
public class Program
{
public static Creator GetCreator()
{
string os = GetOsType(); // определяет ОС
return os switch
{
"windows" => new WindowsCreator(),
"linux" => new LinuxCreator(),
_ => throw new PlatformNotSupportedException()
};
}
// ...
}
Тогда метод CreateButton и использующие его методы не придется никогда переписывать
private readonly Creator _creator = Program.GetCreator();
public Button CreateButton()
{
return _creator.CreateButton();
}
А для поддержки новой ОС потребуется лишь создать еще одну реализацию Creator и добавить одну строчку в точку компоновки приложения, например:
"macos" => new MacosCreator(),
Быстро и просто. Особенно это ощутится, если у вас не только кнопки, а пара сотен других контролов и штук 5 поддерживаемых платформ.
И в этом месте вы подходите к изучению шаблона проектирования "инверсия управления" (IoC, Inversion of Control).