Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/297.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#_Open Closed Principle - Fatal编程技术网

C# 打开/关闭原则-如何处理此开关?

C# 打开/关闭原则-如何处理此开关?,c#,open-closed-principle,C#,Open Closed Principle,我一直在研究开闭原理,它听起来不错,所以我想练习它的教导。 我想把我新发现的知识应用到一个现有的项目中,但马上就有点卡住了 如果出现了一个新的用户类型(这很可能),则需要对其进行更改,但尚未关闭修改。你怎么能绕过这个 从我所读到的,听起来我应该在这里实现一个工厂,而不是应用OCP 谢谢, Kohan内部类UserTreeBuilder { [进口数量(AllowRecomposition=true)] 公共IEnumerable生成器{get;set;} 公共用户treebuilder() {

我一直在研究开闭原理,它听起来不错,所以我想练习它的教导。 我想把我新发现的知识应用到一个现有的项目中,但马上就有点卡住了

如果出现了一个新的用户类型(这很可能),则需要对其进行更改,但尚未关闭修改。你怎么能绕过这个

从我所读到的,听起来我应该在这里实现一个工厂,而不是应用OCP

谢谢, Kohan

内部类UserTreeBuilder
{
[进口数量(AllowRecomposition=true)]
公共IEnumerable生成器{get;set;}
公共用户treebuilder()
{
//从MEF CompositionContainer加载所有生成器
}
公共void BuildUserTree(用户)
{
var builder=Builders.FirstOrDefault(b=>b.CanHandleUserType(user.UserType));
if(builder==null)
{
抛出新异常(“未设置用户类型”);
}否则{
BuildTree();
}
}
}

可用构建器的列表可以像任何“原则”一样使用

来构建,OCP并不是您在任何情况下都必须遵守的规则

我们被告知“偏爱组合而不是继承”,但装饰器和复合模式公开促进继承

类似地,我们被告知“编程到一个接口,而不是一个实现,然而,在我们的应用程序中的某个时刻,我们将不得不实例化一个具有某种描述的具体对象

您的解决方案是一个经典的工厂习惯用法(如果不是完全的工厂方法或抽象工厂模式)。这就是它的意图。试图将OCP应用于它是没有意义的


事实上,通过创建此方法,您实际上可以在代码库的其他部分促进OCP。您的应用程序中的一些其他类现在可以遵守OCP,现在您已将创建分离。

要消除类型切换,您必须将职责移回需要特定于类型的操作的类型。这种类型,在您的例子中是“用户”,拥有关于他自己的所有信息,并且可以根据这些知识轻松调用适当的操作。你必须利用继承

在您的情况下,您必须通过简单的继承或组合来反映用户类型。您的“用户”将拥有一个属性“UserType”,就像在您的示例中一样,但它并没有使其成为一个类似“枚举”的类型,而是成为一个复杂的类型,它继承了一个“IUserType”接口并知道如何构造其特定的依赖项(“UserType”实现了“IUserType”)。“IUserType”可以通过属性(例如返回“ITypeSpectTree”的“IUserType.TypeSpecificTree”)公开特定于类型的属性

因此,在您的示例中,当“用户”升级为高级时,您只需将属性设置为具体的“IUserType”实现(例如PremiumUserType)的新实例,该实现执行其特定操作,例如从您的示例构建高级树(“ITypeSpectTree”实现)以及构建关联类型

这样,通过使用组合和继承消除了switch语句。我们将复杂的“UserType”属性转换为一个单独的类,然后将特定于类型的职责转移到类型本身。 继承,尤其是依赖项反转有助于对对象进行操作(例如,获取特定于用户类型的信息,如(user.IUserType.iuserspecificttree))不知道具体类型。这有助于确保我们对扩展开放。继承也有助于封装特定于类型的行为,使代码关闭以进行修改

如果我们需要更改特定于类型的树的生成方式或此用户类型的行为方式,我们将只触及相关的“IUserType”实现,而不会触及“user”。如果添加了新的用户类型(扩展),它们将必须实现基接口“IUserType”而且,不需要使用任何其他代码(如switch语句)使其工作,也不需要进行更多的类型检查。 为了使其完整并提供更多的可扩展性,“User”类还应该实现一个接口,例如“IUser”,该接口公开用户类型(例如“IUser.IUserType”)。

我将执行以下操作:

abstract class User {
   .
   .
   .
   abstract public void buildTree
}

class FreeLoaderUser: User {
   override public void buildTree()
   {
   }
}

class PremiumUser: User {
   override public void buildTree()
   {
   }
}

 class UnlimitedUser: User {
   override public void buildTree()
   {
   }
}
然后,不再使用每次添加新用户类型并简单调用时都需要修改的方法和开关案例:

user.buildTree();
这样,每当你需要添加一个新的用户类型时,你就可以扩展你的代码,而不是修改。你只需要为新的用户类型添加一个新的类,而不需要接触以前的类


这就是他们所说的“开放-关闭”,当你能够处理它的时候,你为什么要违反它?

公平点,我也这么想。只有当你学到新东西的时候,你才会走出去,并尝试立即使用这些知识来支持你的思想。我会继续寻找一段更合适的代码来重新考虑。干杯。不用担心。走吧od思维训练对我来说也是。我也在学习模式:-)虽然这些不是也不应该是严格的规则,但开关通常是难闻的,其他设计/模式可能更受欢迎,它们对OCP更尊重,没有任何负面缺点。同样地,您也提到过,我个人尝试在任何地方使用接口(对于实例化来说都是安全的,有时甚至可以通过依赖注入等方式进行实例化)。+1对于动态工厂。看,让孩子们自己实现他们的需求是实施OCP的一个关键方法。
user.buildTree();