我正在通过策略模式阅读,并试图实施它,但是我一直坚持确定我认为违反开放式原则的策略实施。
在策略模式中,我们将代码到接口并基于客户端互动,我们将通过策略实施。
现在,如果我们有许多策略,因此我们需要决定使用条件,客户选择了
之类的策略IStrategy str;
if(stragety1) {
str = new Strategy1()
} else if (stragety2) {
str = new Strategy2()
} and so on..
str.run()
现在按照开放闭合原理,上述为扩展开放,但并未对修改
不关闭如果将来需要添加其他策略(扩展),我确实需要更改此代码。
有没有办法可以避免这种方法,或者我们需要如何实现策略模式?
1)您必须将选择/创建 concrete 策略从其用途中分开。IE。使用函数selectStrategy
,将其作为(构造函数)参数等传递
2)无法完全避免有条件的创建,但是您可以将其隐藏(例如,使用一些字典来映射状态=>策略)和/或将其转移到应用程序的另一个级别。最后一种方法非常强大且灵活,但取决于任务。在某些情况下,您可能会将选择/创建放在使用它的相同级别上。在其他情况下,您甚至可能最终以授权选择/创建为最高/最低级别。
2.1)您可以使用Registry
模式,并在添加新策略时避免修改"核心"对象。
这确实不是对修改封闭的,但这是由于您初始化的方式。您正在使用值(ENUM?)来确定应使用哪种策略子类。正如@bpjoshi指出了他们的评论,这更多是一种工厂模式。
Wikipedia讨论了策略模式如何支持开放/封闭的原则,而不是妨碍它。
在该示例中,他们使用具有Brake
策略的Car
类。有些汽车用腹肌刹车,有些则不会。可以给予不同的Car
子类和实例进行制动策略。
要关闭代码以进行修改,您需要以不同的方式选择策略。您想在定义新行为或子类的地方选择策略。您必须重新分配代码,以便在扩展代码的点应用特定策略子类。
我认为,关于修改的关闭存在误解。
1988年,梅耶说:
当您的应用程序使用新功能扩展时,应在可能的时进行工作。
和Rober C. Matrin说:
这个定义显然已经过时了。非常仔细地考虑一下。如果可以扩展系统中所有模块的行为,而无需修改它们,则可以在该系统中添加新功能,而无需修改任何旧代码。这些功能将仅通过编写新代码 而添加。https://8thlight.com/blog/uncle-bob/2014/05/12/theopenclosedprinciple.html
添加一些新代码而不修改旧代码不会与开放闭合原理冲突。
我认为您所指的决定应该是工厂课程的责任。以下是一些示例代码:
public interface ISalary
{
decimal Calculate();
}
public class ManagerSalary : ISalary
{
public decimal Calculate()
{
return 0;
}
}
public class AdminSalary : ISalary
{
public decimal Calculate()
{
return 0;
}
}
public class Employee
{
private ISalary salary;
public Employee(ISalary salary)
{
this.salary = salary;
}
public string Name { get; set; }
public decimal CalculateSalary()
{
return this.salary.Calculate();
}
}
员工类使用策略模式,并遵循开放/封闭的原则,即通过构造函数注入新的策略类型(ISALARY实现),但对修改进行了封闭。
。缺少的作品是创建员工对象的代码,例如:
public enum EmployeeType
{
Manager,
Admin
}
public class EmployeeFactory
{
public Employee CreateEmployee(EmployeeType type)
{
if (type == EmployeeType.Manager)
return new Employee(new ManagerSalary());
else if (type == EmployeeType.Admin)
return new Employee(new AdminSalary());
etc
}
}
这是一个非常简单的工厂模式。有更好的方法可以做到这一点,但这是解释概念的最简单方法。