战略模式与开放原则冲突

时间:2017-11-29 12:55:01

标签: oop design-patterns strategy-pattern open-closed-principle

我正在阅读战略模式,并试图实施它,但我一直坚持决定战略实施,我觉得违反了开放封闭原则。

在策略模式中,我们编码接口并基于客户端交互,我们将传递策略实现。

现在,如果我们有一堆策略,那么我们需要决定使用哪种策略,客户选择像

这样的策略
IStrategy str;
    if(stragety1) {
     str = new Strategy1()
    } else if (stragety2) {
     str = new Strategy2()
    } and so on..
str.run()

现在按照开放式原则,上述内容对扩展名开放,但并未关闭修改

如果我将来需要添加其他策略(扩展名),我需要更改此代码。

有没有办法可以避免这种情况,或者我们需要如何实施战略模式?

4 个答案:

答案 0 :(得分:2)

这确实不会因修改而关闭,但这是由于您初始化的方式。您正在使用值(枚举?)来确定应使用哪个策略子类。正如@bpjoshi指出他们的comment,这更像是一种工厂模式。

维基百科讨论战略模式如何support the Open/Closed Principle,而不是妨碍它 在该示例中,他们使用Car类和Brake策略。有些汽车用ABS制动,有些则没有。不同的Car子类和实例可以给出不同的制动策略。

要关闭代码以进行修改,您需要以不同方式选择策略。您希望在定义新行为或子类的位置选择策略。您必须重构代码,以便在扩展代码时应用特定的策略子类。

答案 1 :(得分:2)

1)您必须将选择/创建 具体 策略与其用途分开。 I. e。使用函数selectStrategy,将其作为(构造函数)参数传递等。

2)无法完全避免条件创建,但您可以隐藏它(例如,使用一些字典来映射state =>策略)和/或将其转移到应用程序的另一个级别。最后一种方法非常强大和灵活,但取决于任务。在某些情况下,您可以将选择/创建放在使用它的同一级别上。在其他情况下,您甚至可能最终将委托选择/创建到最高/最低级别。

2.1)您可以使用Registry模式,并在添加新策略时避免修改“核心”对象。

答案 2 :(得分:0)

我认为,对于修改已关闭存在误解。

1988年,梅耶说:
当您的应用程序使用新功能进行扩展时,可能时,应该可以使用的软件。

和Rober C. Matrin说:

这个定义显然是过时的。 仔细考虑一下。如果系统中所有模块的行为都可以扩展而不进行修改,那么您可以向该系统 添加新功能,而无需修改任何旧代码 。这些功能仅通过编写新代码 来添加 https://8thlight.com/blog/uncle-bob/2014/05/12/TheOpenClosedPrinciple.html

在不修改旧代码的情况下添加一些新代码与Open-Closed Principle不冲突。

答案 3 :(得分:-1)

我认为你所指的决定应该是工厂阶级的责任。以下是一些示例代码:

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();
    }
}

Employee类使用策略模式并遵循开放/封闭原则,即通过构造函数注入对新策略类型(ISalary实现)开放,但不接受修改。

缺少的部分是创建Employee对象的代码,如:

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

    }
}

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