gpt4 book ai didi

针对不同返回类型的 C# 策略设计模式

转载 作者:行者123 更新时间:2023-12-03 16:49:40 25 4
gpt4 key购买 nike

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

最小的例子。

所以我的界面是这样的:

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

为客户定义感兴趣的接口(interface)的上下文类:
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

最佳答案

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

问题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),底层的实际对象也不是,因此这不能是策略模式的实现。这些策略是动态注入(inject)的,因此没有人应该对它们有硬编码的依赖关系。一种可能的实现可能是 -
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);
}

信息 仅当使用该策略的类不对依赖项进行硬编码时,该策略模式才有效,这就是它的全部思想。

您拥有的示例可能不是策略模式的好示例。我试图尽可能地修复它,以便您很好地了解您的实现中出了什么问题。并非所有模式都支持所有场景。这是策略模式的示例实现,与您的非常相似 https://refactoring.guru/design-patterns/strategy/csharp/example .

我希望这有帮助。

备注 我提供的代码不是工作版本。他们可能甚至不会编译,他们只是在那里表达策略模式背后的想法。正确的实现对于每个类都有不同的代码 ParseAParseB
更多 策略模式和 IoC,(控制反转)齐头并进。尝试学习 IoC,您会发现策略模式更容易学习。 https://en.wikipedia.org/wiki/Inversion_of_control

关于针对不同返回类型的 C# 策略设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60587569/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com