不同收益类型的C#策略设计模式

问题描述 投票:3回答:3

我尝试将策略设计模式应用于某些文本内容的解析,其中每个结果在不同的类中表示。

最小示例。

所以我的界面看起来像这样:

public interface IParseStrategy
{
    object Parse(string filePath);
}

实现算法的类:

class ParseA : IParseStrategy
{
    public object Parse(string filePath) => new ConcurrentQueue<ParseAData>();
}

class ParseB : IParseStrategy
{
    public object Parse(string filePath) => new Dictionary<string, ParseBData>();
}

特定的“数据”类:

class ParseAData
{
    public int Id { get; set; }
    public string Name { get; set; }

}

class ParseBData
{
    private byte[] data;

    public byte[] GetData()
    {
        return data;
    }

    public void SetData(byte[] value)
    {
        data = value;
    }
}

为客户定义兴趣界面的上下文类:

class Context
{
    private IParseStrategy _strategy;

    private void SetParsingStrategy(IParseStrategy parseStrategy)
    {
        _strategy = parseStrategy;
    }

    public object TryParse(string filePath, TypeToParse typeToParse)
    {
        object parsedContent = new object();

        try
        {
            switch (typeToParse)
            {
                case TypeToParse.A:
                    SetParsingStrategy(new ParseA());
                    parsedContent = _strategy.Parse(filePath);
                    break;
                case TypeToParse.B:
                    SetParsingStrategy(new ParseB());
                    parsedContent = _strategy.Parse(filePath);
                    break;
                    throw new ArgumentOutOfRangeException(nameof(typeToParse), "Uknown type to parse has been provided!");
            }
        }
        catch (Exception)
        {

            throw;
        }

        return parsedContent;
    }

}

客户端可以在其中选择正确算法的枚举

public enum TypeToParse { A, B }

最后是主要方法:

static void Main(string[] args)
{
    var context = new Context();
    ConcurrentQueue<ParseAData> contentOfA = (ConcurrentQueue<ParseAData>)context.TryParse("file1.whatever", TypeToParse.A);
    Dictionary<string, ParseBData>contentOfB = (Dictionary<string, ParseBData>)context.TryParse("file2.whatever", TypeToParse.B);
}

所以,我的问题是客户端必须知道这些类才能转换返回类型object

如何以更通用的方式重写它,以便编译器将使用var关键字自动推断类型,因此调用将类似于:

        var contentOfA = context.TryParse("file1.whatever", TypeToParse.A);
        var contentOfB = context.TryParse("file2.whatever", TypeToParse.B);

带有黄色标记的推断类型:

enter image description here

c# strategy-pattern
3个回答
0
投票

简单的答案是您无法解决这个问题:

所以,我的问题是客户端必须知道这些类才能转换返回类型对象。

给出的任何答案,用户都需要知道将要返回的对象的类型,只有在知道运行时或上下文类的内部实现之后,上下文类的用户才能知道该类型。 Context类。

但是,这种类型的代码不适合作为接口保证唯一的对象是返回对象。

[如果Context的用户必须将选项传递给函数TypeToParse,则上下文类的用户最好具有2个函数,它们返回正确的类型,例如

class Context
{
    public ParseAData ParseAsA(string filePath)
    {
        ...
    }

    public ParseBData ParseAsB(string filePath)
    {
        ...
    }
}

0
投票

您好,我认为您误解了策略模式。在此线程中阅读有关如何解决问题的更多信息:https://social.msdn.microsoft.com/Forums/en-US/2bbef57c-4172-48a1-b683-faf779d6a415/strategy-pattern-with-specific-return-types?forum=architecturegeneral


0
投票

您正在以错误的方式实施策略模式。请重新阅读有关策略模式的内容,并尝试了解如何使用它。我将尝试在这里指出问题。想法是根据输入或状态(最重要的部分,输入或输出的类型不变)在代码库中注入逻辑。

问题1,上下文永远不应该知道有多种可用策略。它仅知道以下事实:它具有策略的实现,并且必须使用该策略来执行某些操作并返回结果。

因此,上下文类

public object TryParse(string filePath, TypeToParse typeToParse)
{
    object parsedContent = new object();

    try
    {
        switch (typeToParse)
        {
            case TypeToParse.A:
                SetParsingStrategy(new ParseA());...
                break;
            case TypeToParse.B:
                SetParsingStrategy(new ParseB());...
                break;
        }
    }
    ....
}

违反此规定。它有一个开关柜,它知道类型,这是不可能的。适当的实现将类似于-

public object TryParse(string filePath, TypeToParse typeToParse)
{
    object parsedContent = _this._stategy.Parse(filePath); //it should never know which implementation is supplied, in other words wich strategy is applied. Only at runtime t will be decided.
}

问题2,该策略的两类实现具有这样的实现-

class ParseA : IParseStrategy
{
    public object Parse(string filePath) => new ConcurrentQueue<ParseAData>();
}

class ParseB : IParseStrategy
{
    public object Parse(string filePath) => new Dictionary<string, ParseBData>();
}

这也是一种违法行为。你为什么问?因为调用各个类的代码必须知道它们返回的内容。策略模式是一种模式,它并不关心c#是否支持它。 object是C#特定的好东西,可用于类型转换任何对象。但这并不意味着使用对象可以解决所有问题。即使返回类型相同(object),实际的基础对象也不相同,因此这不能作为策略模式的实现。这些策略是动态注入的,因此没有人应该对此有硬编码的依赖性。一种可能的实现方式是-

interface IData
{
}

class ParseAData : IData
{
    public int Id { get; set; }
    public string Name { get; set; }

}

class ParseBData : IData
{
    private byte[] data;

    public byte[] GetData()
    {
        return data;
    }

    public void SetData(byte[] value)
    {
        data = value;
    }
}

public interface IParsedObject 
{
    void process(<Some other dependencies>);
}

public class ConcurrentQueue<T> : IParsedObject where T: ParseAData
{

}

public class ParsedDictionary<T> : IParsedObject where T: ParseBData
{

}


public interface IParseStrategy
{
    IParsedObject Parse(string filePath);
}

//the method will be somesiliar to this 
public IParsedObject TryParse(string filePath, TypeToParse typeToParse)
{
    IParsedObject parsedContent = _this._stategy.Parse(filePath); //it should never know which implementation is supplied, in other words wich strategy is applied. Only at runtime t will be decided.
}

class ParseA : IParseStrategy
{
    public IParsedObject Parse(string filePath) => new ConcurrentQueue<ParseAData>();
}

class ParseB : IParseStrategy
{
    public IParsedObject Parse(string filePath) => new Dictionary<string, ParseBData>();
}

有了这些修改,您现在可以写-

static void Main(string[] args)
{
    var contextA = new Context();
    contentA.SetParsingStrategy(new ParseA());


    var contextB = new Context();
    contextB.SetParsingStrategy(new ParseB());

    var contentOfA = contextA.TryParse("file1.whatever", TypeToParse.A);
    var contentOfB = contextB.TryParse("file2.whatever", TypeToParse.B);
}

static void Main(string[] args)
{
    var context = new Context();
    contentA.SetParsingStrategy(new ParseA());
    var contentOfA = context.TryParse("file1.whatever", TypeToParse.A);

    context.SetParsingStrategy(new ParseB());
    var contentOfB = context.TryParse("file2.whatever", TypeToParse.B);
}

Info策略模式仅在使用策略的类没有对依赖项进行硬编码(即其全部思想)时有效。

您拥有的示例可能不是策略模式的好例子。我试图尽可能地修复它,以便您对实现中的错误有一个很好的了解。并非所有模式都支持所有方案。这是策略模式的示例实现,与您的https://refactoring.guru/design-patterns/strategy/csharp/example非常相似。

我希望这会有所帮助。

我提供的代码不起作用。他们甚至可能不会编译,只是在那里表达策略模式背后的想法。对于每个类别ParseAParseB],正确的实现将具有不同的代码

更多

策略模式与IoC(控制反演)齐头并进。尝试学习IoC,您会发现更容易学习策略模式。 https://en.wikipedia.org/wiki/Inversion_of_control
© www.soinside.com 2019 - 2024. All rights reserved.