C# 拆卸开关盒的设计模式
我需要根据提供的C# 拆卸开关盒的设计模式,c#,design-patterns,switch-statement,solid-principles,open-closed-principle,C#,Design Patterns,Switch Statement,Solid Principles,Open Closed Principle,我需要根据提供的countryid验证特定国家/地区的邮政编码是否是强制性的。目前,我使用switch语句来执行此操作,但此代码打破了打开/关闭实体原则。我想知道在这种情况下如何去掉开关 public class PostCodeVerifyMandatory : IPostCodeVerifyMandatory { public bool IsPostCodeRequired(int countryId, string region) { switch (cou
countryid
验证特定国家/地区的邮政编码是否是强制性的。目前,我使用switch
语句来执行此操作,但此代码打破了打开/关闭实体原则。我想知道在这种情况下如何去掉开关
public class PostCodeVerifyMandatory : IPostCodeVerifyMandatory {
public bool IsPostCodeRequired(int countryId, string region)
{
switch (countryId) {
case 1: //UK
case 12: //Australia
case 29: //Brazil
case 31: //Brunei
case 37: //Canada
case 56: //Denmark
case 105: //Japan
case 110: //South Korea
case 114: //Latvia
case 136: //Moldova
case 137: //Monaco
case 145: //Netherlands
case 165: //Poland
case 166: //Portugal
case 183: //Slovak Republic (Slovakia)
case 189: //Spain
case 196: //Sweden
case 197: //Switzerland
case 199: //Taiwan Region
case 213: //Ukraine
case 215: //USA
case 221: //Vietnam
return true;
case 232: //Ireland
return region == "Dublin";
default:
return false;
}
}
}
您的switch
语句有效地将整数映射为布尔值,默认值为false
因此,在本例中,我只需创建一个具有适当值的字典
。由于这些值几乎是固定的,因此可以在声明中对其进行初始化:
Dictionary<int, bool> dict = new Dictionary<int, bool>() {
{ 1 /* UK */, true },
{ 12 /* Australia */, false }
...etc...
};
Dictionary dict=new Dictionary(){
{1/*UK*/,true},
{12/*澳大利亚*/,假}
等
};
正如@Nick所指出的,爱尔兰的情况意味着您仍然需要一些额外的逻辑,因此您希望字典是private
,并且可以通过IsPostCodeRequired(int,strnig)
方法访问答案
编辑:
正如@JustinHarvey所指出的,最好从数据库中获取这些值
如果你想对开放/封闭原则非常严格,你可以使用设计模式——你可以为每个国家创建一个单独的具体战略对象。如果添加了一个新国家,您将为该国家创建一个新的ConcreteStrategy对象。这样,您就可以为具有特殊规则的国家添加逻辑,而无需触及原始代码。
但是,拥有特殊规则的国家数量可能非常少,因此,除非您真的无法在代码投入生产后对其进行更改,否则这是一种过度工程。可能是这样的:
private Dictionary<int, string> _dict;
protected Dictionary<int, string> CountryDictionary
{
get
{
if (_dict == null)
{
_dict = new Dictionary<int, string>();
_dict.Add(1, "UK");
_dict.Add(12, "Australia");
// and so on
}
return _dict;
}
}
public class PostCodeVerifyMandatory : IPostCodeVerifyMandatory
{
public bool IsPostCodeRequired(int countryId, string region)
{
return CountryDictionary.ContainsKey(countryId);
}
}
private Dictionary\u dict;
受保护词典
{
得到
{
如果(_dict==null)
{
_dict=新字典();
_补充(1,“英国”);
_补充(12,“澳大利亚”);
//等等
}
返回命令;
}
}
公共类PostCodeverify必填项:IPostCodeverify必填项
{
公共bool IsPostCodeRequired(国际国家ID,字符串区域)
{
返回CountryDictionary.ContainsKey(countryId);
}
}
我可能会遵循c2 Wiki页面“”中的建议:
使用数据库或TableOrientedProgramming有时是
适当的“修复”,而不是多态性。例如,存储产品
分类最好在多对多数据库中处理
类别表,而不是case语句
你可以有这样的东西:
public class Country
{
public List<Region> Regions { get; set; }
public bool IsPostCodeRequiredByDefault { get; set; }
}
public class Region
{
private bool? _isPostCodeRequired;
public Country Country { get; set; }
public bool IsPostCodeRequired
{
get { return _isPostCodeRequired ?? Country.IsPostCodeRequiredByDefault; }
}
}
公共类国家
{
公共列表区域{get;set;}
公共bool isPostCodeRequired默认情况下{get;set;}
}
公共类区域
{
私人bool?_isPostCodeRequired;
公共国家{get;set;}
公共bool IsPostCodeRequired
{
获取{return\u isPostCodeRequired??默认情况下Country.isPostCodeRequired;}
}
}
它还有一个好处,就是通过使区域成为一个一流的域概念而不仅仅是一个字符串,来处理次要的“原始困扰”气味。尝试以下方法:
public class PostCodeVerifyMandatory : IPostCodeVerifyMandatory
{
public List<Func<int, string, bool>> Rules { get; private set; }
public PostCodeVerifyMandatory()
{
Rules = new List<Func<int, string, bool>>();
}
public bool IsPostCodeRequired(int countryId, string region)
{
if(Rules == null)
return false;
return (Rules.Any(r => r(countryId, region)));
}
}
public类PostCodeVerifyMandatory:IPostCodeVerifyMandatory
{
公共列表规则{get;private set;}
公共邮政编码必填项()
{
规则=新列表();
}
公共bool IsPostCodeRequired(国际国家ID,字符串区域)
{
如果(规则==null)
返回false;
返回(Rules.Any(r=>r(countryId,region));
}
}
在使用规则集之前,您必须加载规则集:
var simpleCountries = new List<int>
{
1, // UK
12, // Australia
29, // Brazil
56, // Brunei
//..
//..
215, //USA
221 //Vietnam
};
var postCodeVerifier = new PostCodeVerifyMandatory();
// 1 rule for simple countries
postCodeVerifier.Rules.Add((id, region) => simpleCountries.Contains(id));
// Special rule for Ireland
postCodeVerifier.Rules.Add((id, region) => id == 232 && region.Equals("Dublin"));
var a = postCodeVerifier.IsPostCodeRequired(232, "Dublin");
var simpleCountries=新列表
{
1,//英国
12,//澳大利亚
29,//巴西
56,//文莱
//..
//..
215,//美国
221/越南
};
var postCodeVerifier=新的PostCodeVerifyMandatory();
//1简单国家的规则
postCodeVerifier.Rules.Add((id,region)=>simpleCountries.Contains(id));
//爱尔兰特别规则
postCodeVerifier.Rules.Add((id,region)=>id==232&®ion.Equals(“都柏林”);
var a=邮政编码验证程序。IsPostCodeRequired(232,“都柏林”);
或使其完全数据驱动(以字典为例):
var-countries=新字典
{
{1,null},//UK
{12,null},//澳大利亚
{29,null},//巴西
{56,null},//文莱
//..
//..
{215,null},//美国
{221,null},//越南
{232,“都柏林”}//爱尔兰
};
var postCodeVerifier=新的PostCodeVerifyMandatory();
//一条规则适用于所有人
postCodeVerifier.Rules.Add((id,region)=>
国家/地区。集装箱(id)和
(国家[id]??地区)=地区);
我不知道还有什么能让这件事变得更简单。因此,从简单易读的角度来看,这可能仍然是最好的选择。你为什么说它违反了坚实的原则?我想更重要的是,如果值被添加或更改,我会将其放入数据库中,因此,避免重新编译和部署/发货。@Justin如果它是从国家代码到布尔值的简单映射,那将很容易。。。但也有像爱尔兰这样的案例涉及到额外的逻辑。我会关心这个列表是如何维护的,“CountryID”是来自数据库,还是只是在应用程序中硬编码?如果它来自数据库,那么可以有两个表C
var countries = new Dictionary<int, string>
{
{ 1, null }, // UK
{ 12, null }, // Australia
{ 29, null }, // Brazil
{ 56, null }, // Brunei
//..
//..
{ 215, null }, //USA
{ 221, null }, //Vietnam
{ 232, "Dublin" } // Ireland
};
var postCodeVerifier = new PostCodeVerifyMandatory();
// 1 rule for all
postCodeVerifier.Rules.Add((id, region) =>
countries.ContainsKey(id) &&
(countries[id] ?? region) == region);