具有多个可能控制流的面向对象编程函数最佳实践

4
在我的项目中,有一个特殊的函数需要评估以下内容:
  1. 状态 - 由枚举表示 - 大约有6个不同的状态
  2. 左参数
  3. 右参数
左和右参数由字符串表示,但它们的值可以是以下内容:
  1. "_"(通配符)
  2. "1"(整数字符串)
  3. "abc"(正常字符串)
因此,为了涵盖所有可能性,需要评估大约2 * 3 * 6 = 36种不同的逻辑,当然,在一个巨大的函数中使用if-else是不可行的。我已经将上述3个输入封装成一个对象,我将传递给我的函数。
如何使用面向对象编程来解决这个问题?是否有意义创建6个不同子类的主要State类,并带有一个evaluate()方法,然后在各自的方法中进行if else语句检查:
  • 如果左右参数都是通配符,则执行某些操作
  • 如果左边是数字,右边是字符串,则执行其他操作
  • 重复所有有效组合的步骤在每个State子类中
这感觉就像是正确的方向,但也感觉存在大量重复的逻辑(例如检查两个参数是否都是通配符或都是字符串等)对于所有6个子类。然后我的想法是将其抽象化一些并创建另一个子类:
对于每个状态子类,我有stateWithTwoWildCards、statewithTwoString等。
但我觉得这太过头了,过度工程化并且变得“太”具体(我知道这从技术上紧密遵守SOLID,特别是SRP和OCP概念)。对此有何想法?
2个回答

1
可能在这种情况下,类似于模板方法模式的东西会很有用。也就是说,您将在基本的State.evaluate方法中封装所有检查逻辑,并创建几个子类将覆盖的方法。大致如下:
class StateBase
   def evaluate():
       if(bothWildcards)
          evalBothWildcards()
       else if(bothStrings)
          evalBothStrings()
       else if ...
   
   def evalBothWildcards():
      ...
   def evalBothStrings():
      ...

在继承类中,evalBothWildcardsevalBothStrings等方法会被重载。

1
“有大约2 * 3 * 6 = 36种不同的逻辑需要评估。”
“我们可以应用分治技术。”
  • 您有6个状态。可以在此处使用责任链模式来选择适当的状态处理程序
  • 找到所需的状态处理程序后,我们可以应用所需的函数。适当的函数可以视为策略。因此,这是可以应用策略模式的地方。
  • 我们可以按适当的状态将策略分开,并将它们放入简单工厂中,以通过键获取所需的策略。
“这就是我们要做的事情。所以让我们更加深入地了解它。”

责任链模式

“如果您有很多if else语句,则可以使用责任链模式。正如维基百科所说的Chain of Responsibility:”
责任链模式是一种行为设计模式,包含命令对象源和一系列处理对象。每个处理对象包含定义其可以处理的命令对象类型的逻辑;其余的则传递给链中的下一个处理对象。还存在一种机制,在此链的末尾添加新的处理对象。
让我们通过C#的示例来深入了解代码。
这是我们的Argument类,它具有左操作数和右操作数:
public class Arguments
{
    public string Left { get; private set; }

    public string Right { get; private set; }

    public MyState MyState { get; private set; }

    public MyKey MyKey => new MyKey(MyState, Left);

    public Arguments(string left, string right, MyState myState)
    {
        Left = left;
        Right = right;
        MyState = myState;
    }
}

这是你的6个州:
public enum MyState
{
    One, Two, Three, Four, Five, Six
}

这是装饰者模式的开始。这是状态处理程序的抽象,它定义了设置下一个处理程序的行为:
public abstract class StateHandler
{
    public abstract MyState State { get; }

    private StateHandler _nextStateHandler;

    public void SetSuccessor(StateHandler nextStateHandler)
    {
        _nextStateHandler = nextStateHandler;
    }

    public virtual IDifferentLogicStrategy Execute(Arguments arguments)
    {
        if (_nextStateHandler != null)
            return _nextStateHandler.Execute(arguments);

        return null;
    }
}

它的具体实现包括 StateHandler:
public class OneStateHandler : StateHandler 
{
    public override MyState State => MyState.One;

    public override IDifferentLogicStrategy Execute(Arguments arguments)
    {   
        if (arguments.MyState == State)
            return new StrategyStateFactory().GetInstanceByMyKey(arguments.MyKey);
        
        return base.Execute(arguments);
    }
}

public class TwoStateHandler : StateHandler
{
    public override MyState State => MyState.Two;

    public override IDifferentLogicStrategy Execute(Arguments arguments)
    {
        if (arguments.MyState == State)
            return new StrategyStateFactory().GetInstanceByMyKey(arguments.MyKey);

        return base.Execute(arguments);
    }
}

第三个状态处理程序看起来像这样:
public class ThreeStateHandler : StateHandler
{
    public override MyState State => MyState.Three;

    public override IDifferentLogicStrategy Execute(Arguments arguments)
    {
        if (arguments.MyState == State)
            return new StrategyStateFactory().GetInstanceByMyKey(arguments.MyKey);

        return base.Execute(arguments);
    }
}

策略模式
让我们关注下面这行代码:
return new StrategyStateFactory().GetInstanceByMyKey(arguments.MyKey);

以上代码是使用策略模式的示例。我们有不同的方式或策略来处理您的情况。让我展示一下评估您表达式的策略代码。
这是一个策略的抽象:
public interface IDifferentLogicStrategy
{
    string Evaluate(Arguments arguments);
}

它的具体实现:
public class StrategyWildCardStateOne : IDifferentLogicStrategy
{
    public string Evaluate(Arguments arguments)
    {
        // your logic here to evaluate "_" (a wildcard)
        return "StrategyWildCardStateOne";
    }
}

public class StrategyIntegerStringStateOne : IDifferentLogicStrategy
{
    public string Evaluate(Arguments arguments)
    {
        // your logic here to evaluate "1" (an integer string)
        return "StrategyIntegerStringStateOne";
    }
}

第三个策略是:
public class StrategyNormalStringStateOne : IDifferentLogicStrategy
{
    public string Evaluate(Arguments arguments)
    {
        // your logic here to evaluate "abc" (a normal string)
        return "StrategyNormalStringStateOne";
    }
}

简单工厂

简单工厂模式并不存在。然而,它是一个可以通过关键字获取策略实例的地方。这样做可以避免使用多个if else语句来选择正确的策略。 因此,我们需要一个地方来存储状态和参数值的策略。首先,让我们创建MyKey结构体。它将帮助我们区分状态和参数:

public struct MyKey
{
    public readonly MyState MyState { get; }

    public readonly string ArgumentValue { get; } // your three cases: "_", 
        // an integer string, a normal string

    public MyKey(MyState myState, string argumentValue)
    {
        MyState = myState;
        ArgumentValue = argumentValue;
    }
    
    public override bool Equals([NotNullWhen(true)] object? obj)
    {
        return obj is MyKey mys
            && mys.MyState == MyState
            && mys.ArgumentValue == ArgumentValue;
    }

    public override int GetHashCode()
    {
        unchecked // Overflow is fine, just wrap
        {
            int hash = 17;
            hash = hash * 23 + MyState.GetHashCode();
            hash = hash * 23 + ArgumentValue.GetHashCode();
            return hash;
        }
    }
}

然后我们可以创建一个简单的工厂:
public class StrategyStateFactory 
{
    private Dictionary<MyKey, IDifferentLogicStrategy> 
        _differentLogicStrategyByStateAndValue = 
            new Dictionary<MyKey, IDifferentLogicStrategy>()
    {
        { new MyKey(MyState.One, "_"), new StrategyWildCardStateOne() },
        { new MyKey(MyState.One, "intString"), 
            new StrategyIntegerStringStateOne() },
        { new MyKey(MyState.One, "normalString"), 
            new StrategyNormalStringStateOne() }
    };

    public IDifferentLogicStrategy GetInstanceByMyKey(MyKey myKey) 
    {
        return _differentLogicStrategyByStateAndValue[myKey];
    }
}

所以我们已经编写了我们的策略,并将这些策略存储在简单工厂StrategyStateFactory中。
然后我们需要检查上述实现:
StateHandler chain = new OneStateHandler();
StateHandler secondStateHandler = new TwoStateHandler();
StateHandler thirdStateHandler = new ThreeStateHandler();

chain.SetSuccessor(secondStateHandler);
secondStateHandler.SetSuccessor(thirdStateHandler);

Arguments arguments = new Arguments("_", "_", MyState.One);    
IDifferentLogicStrategy differentLogicStrategy = chain.Execute(arguments);

string evaluatedResult = 
differentLogicStrategy.Evaluate(arguments); // output: "StrategyWildCardStateOne"

我相信我已经给出了如何完成这个基本想法的概述。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接