策略模式和开放式原则冲突



我正在通过策略模式阅读,并试图实施它,但是我一直坚持确定我认为违反开放式原则的策略实施。

在策略模式中,我们将代码到接口并基于客户端互动,我们将通过策略实施。

现在,如果我们有许多策略,因此我们需要决定使用条件,客户选择了

之类的策略
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
    }
}

这是一个非常简单的工厂模式。有更好的方法可以做到这一点,但这是解释概念的最简单方法。

最新更新