js 使用多态替换条件语句

用多态替换条件语句是一种众所周知的重构模式。 如果您不熟悉该模式,可以在此处查看 。 但是,一旦类中有多个条件检查所基于的字段,该基本解决方案便会开始崩溃。 我们将研究一些有关如何使用这些可能性的想法。

有很多方法可以解决,因此我们将从最简单到最困难的工作,始终使用简单的示例来尽可能减少混乱。 那么,最简​​单的情况是什么? 看一看:

public class ClassWithConditionals
{private boolean conditional1;private EnumeratedType conditional2;public ClassWithConditionals(boolean cond1, EnumeratedType cond2){conditional1 = cond1;conditional2 = cond2;}public void method1(){if(conditional1){//do something}else{//do something else}}public void method2(){switch(conditional2){case CASE1://do somethingbreak;case CASE2://do something elsebreak;case CASE3://do something entirely differentbreak;}}
}enum EnumeratedType
{CASE1,CASE2,CASE3
}

因此,在此示例中,我们有ClassWithConditionals在其方法中使用的两个不同字段。 在一个合适的示例中,您将假设使用的方法不只是给定的两个,但在示例中我们只需要两个。 如果每种条件只使用一种方法,则无需担心,因为维护成本仍然很低。 但是,只要执行这种条件检查的方法数量增加,就应该考虑进行这种重构。

通常,如果您要遵循用多态替换条件,您将最终得到六个类来解决此问题: booleanenum每种组合都需要一个。 取而代之的是,我们将使用合成。

那么,第一步是什么? 首先,我们可能应该使用enum类型。 enum可以有自己的方法,可以以允许其根据特定enum做不同事情的方式定义这些方法。 因此,让我们将enum eratedType更改为如下形式:

enum EnumeratedType
{CASE1(){public void doSomething(){//do something}},CASE2(){public void doSomething(){//do something else}},CASE3(){public void doSomething(){//do something entirely different}};public abstract void doSomething();
}

现在, method2仅需要将自身委托给conditional2.doSomething()

现在让我们修复boolean 。 我们创建一个接口,该接口对所有非封装类(为进行测试,可能还有该包)都私有,称为Conditional1 。 然后我们用TrueFalse对其进行子类化。 这是代码:

interface Conditional1
{static Conditional1 TRUE = new True();static Conditional1 FALSE = new False();void doSomething();
}class True implements Conditional1
{public void doSomething(){//do something}
}class False implements Conditional1
{public void doSomething(){//do something else}
}

我决定在接口上创建TRUEFALSE实例的原因很简单:它们都是无状态类,这意味着每个实例都具有多个实例是没有意义的。 它还允许我们像enum一样调用它们。

同样,现在主要类只需要委托。 这是固定类现在的样子

public class ClassWithConditionals
{public static ClassWithConditionals with(boolean cond1, EnumeratedType cond2){Conditional1 conditional1;if(cond1)conditional1 = Conditional1.TRUE;elseconditional1 = Conditional1.FALSE;return new ClassWithConditionals(conditional1, cond2);}private Conditional1 conditional1;private EnumeratedType conditional2;ClassWithConditionals(Conditional1 cond1, EnumeratedType cond2){this.conditional1 = cond1;this.conditional2 = cond2;}public void method1(){conditional1.doSomething();}public void method2(){conditional2.doSomething();}
}

这里有些奇怪。 我们已经用另一个替换了一个条件。 我们的构造函数足以接受一个Conditional1 ,但是我们有一个静态工厂方法,该方法仍然采用boolean并对此进行条件检查。

考虑到从技术上讲,除非有多种方法在进行检查,否则我们不会重构此代码,因此,我们进行了许多检查并将其归为一类。 同样,在工厂中通常认为有条件的还可以,将所有检查都强制在一个地方,并允许多态性从那里接管。 您不必使用静态工厂方法作为工厂,但是它是最快速,最简单的即时设置方法。 允许调用新ClassWithConditionals对象的创建代码的代码仍然可以按过去的方式传递boolean的另一个好处是,它允许我们封装和隐藏基于条件的类的实现细节。 新ClassWithConditionals创建者无需担心创建Conditional1对象,甚至无需知道它的存在。

我们仍然希望构造函数接受Conditional1对象,这有两个原因:1)它将条件逻​​辑保存在工厂中,而不是构造函数中,后者是首选,并且2)它允许我们传递Conditional1对象的测试双精度。

实际上,由于第2点,我们应该经常考虑将enum转换为更类似于Conditional1的静态实例。 这将允许您更多地使用测试双打。 它还将有助于继承或通过合成进行扩展,这将在稍后进行讨论。

可以想到很多小变化。 首先,条件boolean不需要booleanenum 。 可以有一组基于数字或其他条件的条件表达式。 通常,在这些情况下,我们用小的帮助程序方法替换支票以使其更清晰,即if(numberOfPeople <= 3)...变成if(isACrowd(numberOfPeople))... 我们可以更进一步,并创建通过工厂创建的GroupsOfPeople层次结构。 如果工厂的值为1,则返回SinglePerson ; 给定2,则返回Company对象; 给定3或更多,它将返回Crowd对象。 这些对象中的每个对象都有其自己的方法,这样可以帮助减少原始类中的代码量。

另一个变化是当不同的条件字段集分层在一起时( if(condition1 && condition2)等)。 为了解决这个问题,您可以走继承路线并创建爆炸式的类以覆盖所有组合。 另一种选择是用较小的层次结构替换一个条件对象,该层次结构接受委托方法中的其他条件对象,在那里它仍然具有一些条件代码,但是可读性更强。 例如,您可以将使用两个布尔值的类转换为如下形式:

public class ClassWithConditionals
{public static ClassWithConditionals with(boolean condition1, boolean condition2){Conditional1 cond1;if(condition1)cond1 = Conditional1.TRUE;elsecond1 = Conditional1.FALSE;return new ClassWithConditionals(cond1, condition2);}private Conditional1 condition1;private boolean condition2;ClassWithConditionals(Conditional1 condition1, boolean condition2){this.condition1 = condition1;this.condition2 = condition2;}public void method(){condition1.method(condition2);}
}interface Conditional1
{static Conditional1 TRUE = new True();static Conditional1 FALSE = new False();void method(boolean condition2);
}class True implements Conditional1
{public void method(boolean condition2){if(condition2){//do something}else{//do something else}}
}class False implements Conditional1
{public void method(boolean condition2){if(!condition2){//do something really different}//and do this}
}

Condition1method接受一个布尔值,然后使用它进行更多的条件处理。

此外,如果全部逻辑允许,您可以创建一组类来替换其中一个条件,然后让其创建代码接受其他条件,以便确定其一部分创建。 例如:

public class ClassWithConditionals
{public static ClassWithConditionals from(boolean condition1, boolean condition2){return new ClassWithConditionals(Conditional1.from(condition1, condition2));}private Conditional1 conditionOne;ClassWithConditionals(Conditional1 conditionOne){this.conditionOne = conditionOne;}public int method(){return conditionOne.method() * -6;}
}interface Conditional1
{static Conditional1 from(boolean condition1, boolean condition2){if(condition1)return True.with(condition2);elsereturn False.with(condition2);}int method();
}class True implements Conditional1
{public static True with(boolean condition2){if(condition2)return new True(5);elsereturn new True(13);}private int secondary;public True(int secondary){this.secondary = secondary;}public int method(){return 2 * secondary;}
}class False implements Conditional1
{public static False with(boolean condition2){if(condition2)return new False((x, y) -> x - y, 31);elsereturn new False((x, y) -> x * y, 61);}private final BinaryOperator operation;private final int secondary;public False(BinaryOperator operation, int secondary){this.operation = operation;this.secondary = secondary;}public int method(){return operation.apply(4, secondary);}
}

对于True ,第二个条件决定method计算中的次要数字。 在False ,它会执行此操作并找出要应用于计算的运算符。

我不确定是否会发生类似的事情,但是如果确实发生了,您现在知道了一种解决方法。

总的来说,这整套重构实质上将代码从单个类更改为Facade。 它需要大量的新类,并且使您可以使用与以前的单个类几乎完全相同的方式来使用整个工具包和kaboodle,唯一真正的区别是调用静态工厂方法而不是构造函数。

这不是特别重要; 我只是想向您指出。

希望您不必担心继承或“通过合成扩展”此类。 但是您可能必须这样做。

如果您要编写的扩展仅真正改变了条件对象的功能,则可以简单地编写一个新的Factory,为构造函数提供一组新的条件对象。 例如,您可以将此静态工厂方法添加到ClassWithConditionals的最新版本中:

public static ClassWithConditionals different(int value)
{return new ClassWithConditionals(new SimpleConditional1(value));
}

SimpleConditional1看起来像这样

class SimpleConditional1 implements Conditional1
{private final int value;public SimpleConditional1(int value){this.value = value;}public int method(){return value;}
}

除此之外,您还可以提供原始需要的任何条件对象,并覆盖您需要覆盖的所有方法。

因此,这就是我用更多的OO选项替换多个条件的结果。 您还有其他方法可以做到吗? 您是否有一个无法奏效的示例,您想让我大惊小怪? 让我知道,我会解决。

谢谢阅读。

翻译自: https://www.javacodegeeks.com/2015/01/replacing-multiple-conditionals-with-polymorphism-and-composition.html

js 使用多态替换条件语句

js 使用多态替换条件语句_用多态和组成替换多个条件相关推荐

  1. python控制语句中的条件语句_『Python』条件控制语句

    Loading... ## 1. 条件语句 ``` Python条件语句是通过一条或者多条语句的执行结果(True或False)来决定执行的代码块. ``` ``` 在Python中, 指定任何非0和 ...

  2. 循环语句与条件语句_在PHP中混合条件语句和循环

    循环语句与条件语句 As mentioned earlier, the looping statement is executing a particular code as long as a co ...

  3. 单片机c语言条件语句,单片机c语言教程:C51复合语句和条件语句

    曾经在BBS上有朋友问过我{}是什么意思?什么作用?在  C  中是有不少的括号,如{},[],()等,确实会让一些初入门的朋友不解.在 VB 等一些语言中同一个()号会有不一样的 作用,它能用于组合 ...

  4. python编程的条件语句_自学Python编程【第五节】if条件语句

    我们已经能让程序程序判断我们输入的值了,但这程序还是有点呆,不管怎样都要把话说三遍.因为到目前为止,我们的程序都是按照顺序从上到下一行接一行地执行.有同学发来问题了:怎么能让它根据我们输入的结果来选择 ...

  5. shell if多个条件判断_萌新关于Excel VBA中IF条件判断语句的一点心得体会

    作者:金人瑞 <Excel VBA175例无理论纯实战教程>学员 最近正在学习郑广学老师的VBA 175例教程,这是一篇新手向的文章,也是一个新手的总结,高手可以批评文章中的不足之处,也可 ...

  6. 满足多个条件的JAVA语句_关于Java:关于具有多个条件的If语句的快速问题

    本问题已经有最佳答案,请猛点这里访问. Possible Duplicate: && (AND) and || (OR) in Java IF statements 这是一个我可能早在 ...

  7. sql语句用变量替换表名_使用内存优化表替换SQL临时表和表变量

    sql语句用变量替换表名 TempDB usage can be considered as a performance bottleneck for workloads that use SQL t ...

  8. mysql存储过程判断多个条件语句_存储过程里多条件判断(SQL组合查询)

    我存储过程里想实现多个传入参数的判断,里面有7个传入参数条件. CREATE PROCEDURE sp_tbWasteSource_Search ( @sd   datetime,           ...

  9. python 替换文本 通配符_使用通配符搜索和替换文本文件中的字符串

    尝试在python中对文本文件的内容使用通配符进行搜索/替换: 如果文本文件的内容看起来像:"all_bcar_v0038.ma"; "all_bcar_v0002.ma ...

最新文章

  1. UDSMProt:蛋白质分类通用深度序列模型
  2. Keras框架训练模型保存及载入继续训练
  3. android studio3.0升级,升级androidStudio3.0的问题
  4. Beetlsql自定义生成entity,mapper,md代码
  5. deltasql 1.5.5 发布,数据库模型版本控制
  6. 公钥、私钥、数字签名和数字证书的概念及解密
  7. ISO14001与ISO45001都是什么认证?
  8. Linux socks5转http
  9. separated by semicolons
  10. 张朝阳开课手推E=mc²,李永乐现场狂做笔记!CEO当太久都忘了他是MIT物理博士...
  11. 计算机创新论文特点,计算机应用技术的创新分析
  12. 《黑白团团队》第九次团队作业:Beta冲刺第二天
  13. c1语言水平要多久,「西班牙留学」零基础到西班牙读语言,多久能到C1?
  14. python编写自己的股票系统
  15. ATMEL芯片系列介绍0
  16. css裁剪属性----clip-path
  17. OB52 记账期间变式和公司主数据关联关系
  18. windows下安装ruby on rails
  19. 苹果cms模板_苹果cms怎么更换模板?
  20. 微信小程序商城高并发解决方案

热门文章

  1. jzoj2700-数字【数论,LCM】
  2. [CF995F] Cowmpany Cowmpensation(树形dp,拉格朗日插值)
  3. 汇编语言(十八)之求两个数的最大公约数
  4. JVM内存管理------垃圾搜集器参数精解
  5. 全球如何保证区块生成是匀速的?
  6. C++描述杭电OJ 2016.数据的交换输出 ||
  7. 今天就唠叨唠叨吧……
  8. 2017蓝桥杯省赛---java---B---7(日期问题)
  9. 二叉树的前中后序查找+思路分析
  10. 逆波兰表达式中缀表达式转换为后缀表达式