不用输入学术定义,就可以说,当您具有执行操作的客户代码(上下文)时,可以使用“策略模式”,并且可以用不同的方式(算法)来实现此操作。例如: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);
}
}
}
}
我是否错误地认为这是与策略模式不同的模式? (即使我在上面的代码中调用了Strategy,是因为我在某些场合似乎都这样)
如果此问题与策略模式所解决的问题不同,那么它是哪个模式?
答案 0 :(得分:1)
这实际上不是一种策略模式,因为strategy pattern in Wikipedia中的定义是:
在计算机编程中,策略模式(也称为 策略模式)是一种行为软件设计模式 在运行时选择算法。而不是实施一个 直接使用算法,代码会收到有关 一族要使用的算法。[1]
您没有选择要在运行时执行的算法,只是检查条件以查看文件类型是否满足条件,然后执行该算法。
您希望这种情况会改变吗?您是否需要将其扩展,以便将来如果您需要根据文件类型执行不同的代码,可以轻松。
如果对这些问题的回答是是,那么您可以保留策略并进行少量更改。
首先定义基本策略类,该类定义要执行的代码
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
Execute 方法。
如果这确实看起来像是一种矫kill过正,并且您不需要使用新的行为来扩展此解决方案,那么您唯一想要的就是能够添加新的条件,然后采用另一种方法。
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
类中的好处,如果您需要新条件而不用触摸客户端代码。