Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 拆卸开关盒的设计模式_C#_Design Patterns_Switch Statement_Solid Principles_Open Closed Principle - Fatal编程技术网

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