设计模式:策略






4.57/5 (12投票s)
设计模式:策略
很多时候,我们需要在不改变使用它的客户端代码的情况下,更换某个算法。在这篇文章中,我想展示一个我遇到的并使用了策略模式的用例。
它是什么?
这是 GoF 书中对该模式的官方定义
定义一系列算法,将每个算法封装起来,并使它们可以互换。策略模式允许算法独立于使用它的客户端而变化。
用例:获取外部 IP 地址
在一个我正在开发的应用程序中,我需要获取应用程序运行的计算机的外部 IP 地址。实现这一点有多种方法。这看起来是一个很好的机会来使用策略模式,因为我希望能够轻松地在不同的方法之间切换。
实现
接口非常简单
public interface IIpCheckStrategy
{
string GetExternalIp();
}
有些服务以 JSON 格式返回数据,有些服务包含额外的文本。但是,通过将算法封装在各自的类中,客户端代码不必担心解析这些不同的返回值。这在每个类中处理。如果某个服务更改了其输出并破坏了实现,我可以通过更改实例化类的代码来恢复。
接口的具体实现如下。它们实现了 IIpCheckStrategy
接口,并负责获取数据并将解析后的 IP 地址作为 string
返回。
AWS IP 检查器
public class AwsIPCheckStrategy : IIpCheckStrategy
{
public string GetExternalIp()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://checkip.amazonaws.com/");
string result = client.GetStringAsync("").Result;
return result.TrimEnd('\n');
}
}
}
DynDns IP 检查器
public class DynDnsIPCheckStrategy : IIpCheckStrategy
{
public string GetExternalIp()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://checkip.dyndns.org/");
HttpResponseMessage response = client.GetAsync("").Result;
return HelperMethods.ExtractIPAddress(response.Content.ReadAsStringAsync().Result);
}
}
}
自定义 IP 检查器
public class CustomIpCheckStrategy : IIpCheckStrategy
{
public string GetExternalIp()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://check-ip.herokuapp.com/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add
(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("").Result;
string json = response.Content.ReadAsStringAsync().Result;
dynamic ip = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
string result = ip.ipAddress;
return result;
}
}
}
选择算法
算法的使用者可以选择任何实现 IIpCheckStrategy
接口的类,并在它们之间切换。例如
class StrategyClient1
{
public void Execute()
{
IIpCheckStrategy ipChecker;
ipChecker = new DynDnsIPCheckStrategy();
Console.WriteLine(ipChecker.GetExternalIp());
ipChecker = new AwsIPCheckStrategy();
Console.WriteLine(ipChecker.GetExternalIp());
ipChecker = new CustomIpCheckStrategy();
Console.WriteLine(ipChecker.GetExternalIp());
Console.ReadKey();
}
}
此外,在某些情况下,要使用的类名可以存储在配置文件中,以便在不重新编译应用程序的情况下在运行时更改它。例如
class StrategyClient2
{
public void Execute()
{
string ipcheckerTypeName = ConfigurationManager.AppSettings["IPChecker"];
IIpCheckStrategy ipchecker =
Assembly.GetExecutingAssembly().CreateInstance(ipcheckerTypeName) as IIpCheckStrategy;
Console.WriteLine(ipchecker.GetExternalIp());
}
}
配置中的 appSettings
将如下所示
<appsettings>
<add key="IPChecker" value="Strategy.AwsIPCheckStrategy">
</add></appsettings>
资源