在不输入学术定义的情况下,假设在具有执行操作的客户端代码(上下文)时使用了策略模式,并且可以以不同的方式(算法)实现此操作。例如:https://www.dofactory.com/net/strategy-design-pattern
哪种策略(或算法)将在许多情况下取决于某些输入条件。这就是为什么有时将策略模式与工厂模式结合使用的原因。客户端将输入条件传递给工厂。那么工厂就知道要制定什么样的策略了。然后,客户端执行创建的策略的操作。
然而,我在几个场合遇到了一个问题,但在我看来却恰恰相反。要执行的操作总是相同的,但只能根据一系列输入条件来执行。例如:
public interface IStrategy
{
string FileType { get; }
bool CanProcess(string text);
}
public class HomeStrategy : IStrategy
{
public string FileType => ".txt";
public bool CanProcess(string text)
{
return text.Contains("house") || text.Contains("flat");
}
}
public class OfficeStrategy : IStrategy
{
public string FileType => ".doc";
public bool CanProcess(string text)
{
return text.Contains("office") || text.Contains("work") || text.Contains("metting");
}
}
public class StragetyFactory
{
private List<IStrategy> _strategies = new List<IStrategy>{ new HomeStrategy(), new OfficeStrategy() };
public IStrategy CreateStrategy(string fileType)
{
return _strategies.Single(s => s.FileType == fileType);
}
}现在,客户端代码将从某个存储库获取文件,并将文件保存在数据库中。这就是操作,将文件存储在数据库中,这取决于文件的类型和每个文件的特定条件。
public class Client
{
public void Execute()
{
var files = repository.GetFilesFromDisk();
var factory = new StragetyFactory();
foreach (var file in files)
{
var strategy = factory.CreateStrategy(file.Type);
if (strategy.CanProcess(file.ContentText))
{
service.SaveInDatabase(file);
}
}
}
}我是否错误地认为这是一种与战略模式不同的模式?(尽管我在上面的代码中调用了策略,因为我在几次场合都是这样的)
如果这个问题与策略模式所解决的问题不同,那是哪种模式呢?
发布于 2020-01-15 08:48:27
并不是真正的战略模式,因为正如维基百科的策略模式中的定义所说:
在计算机编程中,策略模式(也称为策略模式)是一种行为软件设计模式,它允许在运行时中选择算法。代码不是直接实现单个算法,而是接收运行时指令,说明在一系列算法中使用哪种算法。
您没有选择在运行时执行的算法,只需检查条件,看看文件类型是否满足条件,然后执行该算法。
你认为这种情况会永远改变吗?您是否需要这是可扩展的,以便将来如果您需要根据文件类型执行不同的代码,您可以很容易地执行它。
如果对这些问题的回答是yes,那么您可以保留策略并应用很少的更改。
首先定义定义要执行的代码的基本策略类。
public abstract class StrategyBase
{
public abstract bool CanProcess(string fileType);
public virtual void Execute(File file)
{
_service.SaveInDatabase(file);
}
}你的策略改变为从基础开始。
public class HomeStrategy : StrategyBase
{
public string FileType => ".txt";
public override bool CanProcess(string text)
{
return text.Contains("house") || text.Contains("flat");
}
}//为其他战略实施同样的战略.
正如在评论中提到的,它并不是一个真正的工厂,因为它没有为每一个呼叫创建一个新的策略。它更像是一个提供基于文件类型的执行策略的提供者。
public class StragetyProvider
{
private List<StrategyBase> _strategies = new List<StrategyBase>{ new HomeStrategy(), new OfficeStrategy() };
public StrategyBase GetStrategy(string fileType)
{
return _strategies.FirstOrDefault(s => s.CanProcess(fileType));
}
}因此,客户端代码变得简单得多:
public class Client
{
public void Execute()
{
var files = repository.GetFilesFromDisk();
var provider = new StragetyProvider();
foreach (var file in files)
{
var strategy = provider.GetStrategy(file.Type);
strategy?.Execute(file);
}
}
}注意,当您需要添加新条件时,只需实现一个从StrategyBase派生的新类,并将其添加到提供程序中的策略列表中,而不需要进行其他更改。如果您需要为某些新的文件类型执行不同的逻辑,您将创建新的策略和override执行方法,仅此而已。
如果这看起来确实有点过火,并且您不需要用新的行为来扩展这个解决方案&您唯一想要的就是能够添加新的条件,那么可以使用另一种方法。
public interface ISatisfyFileType
{
bool Satisfies(string fileType);
}
public class HomeCondition : ISatisfyFileType
{
public string FileType => ".txt";
public bool Satisfies(string text)
{
return text.Contains("house") || text.Contains("flat");
}
}
// the rest of conditions把所有的条件组合成一个
public class FileConditions
{
private List<ISatisfyFileType> _conditions = new List<ISatisfyFileType>{ new HomeStrategy(), new OfficeStrategy() };
public bool Satisfies(string fileType) =>
_conditions.Any(condition => condition.Satisfies(fileType));
}客户:
public class Client
{
public void Execute()
{
var files = repository.GetFilesFromDisk();
var fileTypeConditions = new FileConditions();
foreach (var file in files)
{
if (fileTypeConditions.Satisfies(file.ContentText))
{
service.SaveInDatabase(file);
}
}
}
}这还可以实现一个新条件,并在不接触客户端代码的情况下将其添加到FileConditions类中。
https://stackoverflow.com/questions/59746652
复制相似问题