你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

通过枚举来巧妙干掉if-else的方案

[复制链接]
gaosmile 发布时间:2020-9-29 22:30
场景:当我们接收到一些数据需要对其进行处理时,由于它们来自于不同的渠道(如:腾讯,头条),不同渠道所需的处理方式不同,下面我们写一个简单Demo来实现该的场景。
9 J: J) o$ Y. m' _" x+ d2 j6 ~5 {* f
解决思路! G3 N  Z; \  I  ]
1、首先构建一个 GeneralChannelRule 基础规则抽象类,定义一个抽象方法process(),不同的渠道都需要实现该抽象方法。

7 }  [- R/ u# F- w8 C6 S
public abstract class GeneralChannelRule {! c$ O. f$ u3 F, f  t
public abstract void process();
0 e  v( N* k) \5 T}
! m& H/ |" x4 i; C
* d0 {' k# E) Z; C
2、编写一个腾讯的规则类,定义具体对于腾讯渠道数据的处理逻辑
2 d7 k- d" o2 r
public class TencentChannelRule extends GeneralChannelRule
7 \. N1 ~* c" V1 u: H$ ^0 ]" x: \  M   @Override
0 Z0 X! F5 [, Z( \4 h    public void process() {
6 T, j! Z  F) I1 c- n8 h% e7 w3 r3 M        // Tencent处理逻辑6 a/ G6 i8 q$ n: D0 u
    }
& w$ r! e- Z) `* O. O}6 r, O* s2 q. ~/ _% d
/ I) P1 E3 @: f$ X
3、编写一个头条的规则类,定义具体对于头条数据的处理逻辑

( f4 _+ M( Q# X0 D% f3 x4 D, r* |
public class TouTiaoChannelRule extends GeneralChannelRule8 g+ X" j) d! _) o0 o7 ]) J: `; G
   @Override
7 P+ [# o, w- |/ J3 h2 X( F    public void process() {! j+ u8 H3 k& h* a9 t: m% e% U& Y
        // TouTiao处理逻辑# _+ M' b0 J, p6 W3 g& z" L
    }2 A5 K* }! d4 F, q+ A' }
}
& S  A1 W  ^( y% T2 V

  ~. H/ [& @' {' y
4、建立一个简单的枚举类

5 }0 }  `0 ^; o6 u8 f7 B7 Q5 N
public enum ChannelRuleEnum {& ^% {: x" N* j% g# p
    /**+ p" L6 n/ E- o  x( N( ^& A/ Z
     * 头条! I" d) g# b6 ^3 ]% M& z$ K; a6 Q7 I
     *// {# K2 w; Q# ^* m2 N+ e' ]
    TOUTIAO("TOUTIAO"),
$ I! T/ K, ]7 a; G* ^7 u    /**
. v3 E! p9 t4 u2 C. r" ]5 `9 A     * 腾讯% D% N8 ?8 s2 v0 }
     */0 ~/ x) N5 c1 l! L
    TENCENT("TENCENT"),2 @0 W  ?# g# M, y5 k
    ;0 E# z3 F! f% h6 y8 L
  ....# n: S6 E9 }  [3 E& l( r
}5 C. V, |4 a4 C; Y# c8 d

/ X3 q( a1 d- L
5、使用规则对数据进行处理。
( V# W0 ^7 B9 d, P7 Q8 c: j' }
public static void main(String[] args) {
, M. X5 i8 D& c* r& T* O        //这里我们模拟接收到的数据,其渠道为为TOUTIAO,来自头条的数据0 @. g6 e% g7 p1 ?+ C- x
        String sign = "TOUTIAO";- ^- w0 S2 n- d, q% l. A
        GeneralChannelRule rule;0 b# C. y8 j* J; H
        //根据对应渠道获取对应的具体规则实现类
2 u2 [3 b! _; P! c7 u2 {        if (ChannelRuleEnum.TENCENT.code.equals(sign)) {/ }0 J4 {: S5 h/ \
            rule = new TencentChannelRule();' A' D0 a) g  r7 N
        } else if (ChannelRuleEnum.TOUTIAO.code.equals(sign)) {
  e) }5 g2 I5 h# {5 r3 y            rule = new TouTiaoChannelRule();
( X% j, X" {( s! i4 F        } else {
" S2 B; X: ~; o) b: J            //匹配不到6 Y3 A" t" }, ?0 j1 U4 f' i9 ]
        }
: j. `2 F+ K" \( S        //执行7 Q7 c& d0 A; U/ c. ?
        rule.process();
% f6 }6 M/ I* x2 h* E4 ~    }

! ?0 S4 B7 S5 N! T
解析:如果通过上面的方式,则存在则两个缺点。

: Z& K6 g* Y  ~$ R7 m
当我们需要新增新的渠道的时候,需要对main方法中的逻辑进行修改调整。这违背了设计模式中的开放封闭规则。开放封闭原bai则的核心的思想是软件实体是可扩du展,而不可zhi修改的。

7 z# j5 P1 f1 J: Y  _7 N$ ~2 v6 [
也就是说,对扩展是开dao放的,而对修改是封闭的

# ^2 ~" X& S9 v( u% E2 F9 v! l
新增渠道后,修改代码会产生大量的if else,不太优雅。为了解决以上的两个问题,我们可以借助枚举类来巧妙优化。
% `( S; i0 P8 V7 [) w7 |# B
新的思路
2 h# q/ g. R/ g  [6 y0 A6 g5 c
1、下面我们调整一下枚举类,增加一个GeneralChannelRule属性,并且给对应渠道构建对应的GeneralChannelRule实现类,新增一个match() 匹配方法。
) m- G1 j! ?% F6 c" u: E' u$ l
public enum ChannelRuleEnum {
7 a2 f* b( H" O. b+ D$ N$ z3 @$ d8 v& P7 q+ S) d5 D, J) d6 z" J
    /**
; g( j+ B# ~: G     * 头条
) N8 |& p# O# p# o# v) q) n6 t     */
# P# E0 y7 I: `9 u) x" d4 |% B, G    TOUTIAO("TOUTIAO",new TouTiaoChannelRule()),
+ A0 F1 l% m; T3 h7 D    /**
% Z3 P- b% r  e, B3 Y; l     * 腾讯
1 k. N0 V+ P6 x1 z     */
- r% A5 d5 \& R) @0 \( x    TENCENT("TENCENT",new TencentChannelRule()),0 L! k: Z: f7 |  ?
    ;
9 l, i$ J/ e; U9 G8 j- ~2 M) ]; E4 y7 M: m$ G8 ^) ~
    public String name;  @, f# S' \, j( C% a, j) x

. ?5 R5 w% |( t- H, ]; E    public GeneralChannelRule channel;$ r2 u  k* a3 `* G
. E7 x0 t5 g# V$ ]8 P. t) e
    ChannelRuleEnum(String name, GeneralChannelRule channel) {" z' v. ~3 M7 T; m# H7 u
        this.name = name;/ z, V! U' [% u# g' Q' t8 @; W
        this.channel = channel;  I0 q7 [9 \, b' w
    }
2 o' h  S, v% X! n9 X; f
5 e& D! h: z; q6 }9 d) w- J' w  //匹配2 z& f# j) y2 \' I2 Z' ?  Q
    public static ChannelRuleEnum match(String name){
" I: {8 w: t/ @3 g5 h8 K- K        ChannelRuleEnum[] values = ChannelRuleEnum.values();
, H& p/ q; z9 F+ x% A        for (ChannelRuleEnum value : values) {
& X& Q1 {! M# O) {            if(value.name.equals(name)){
  K( `7 c- x' B( H! {8 y& U- e                return value;0 c: T- j7 j- M9 O9 r9 v, {9 y
            }
4 O5 \2 ^2 j+ A& S        }6 b8 X2 s/ c5 O/ i& A
        return null;, z: Y) ]( G! b/ e8 Z# L
    }5 H) R$ t2 t# z1 }
    public String getName() {6 M( }2 v( U: r# t1 Y" S& U+ `
        return name;
6 s8 y% R4 p6 T" A    }& |5 m3 X# A* ]) E( L1 X% k

; c3 Z( K7 z; T" p; h9 G    public GeneralChannelRule getChannel() {
0 F) W( A0 h6 w' ^9 V1 Y        return channel;
) K# O5 L# y* S- [2 t    }
& O' O1 {. X6 D. v/ S6 Y}
, \  S- w1 i/ F# d6 b: {8 m% \2 h5 k- K; j) X. ~

4 ~7 ]! t% V4 k4 X# d0 ?1 Q; E: E* S' B& L# @% z" L7 p7 N
2 [1 I6 c  h) x. O  H: K
2、改写程序
& G: I% ]# w; `+ b* a3 x+ _8 j! Z
public static void main(String[] args) {
' J' }7 l0 T% S/ v; E' O- U2 f        String sign = "TOUTIAO";
% u% F( {. J, M% Y6 g9 o5 V        ChannelRuleEnum channelRule = ChannelRuleEnum.match(sign);( B6 i+ Q) v1 a! F! ?& I
        GeneralChannelRule rule = channelRule.channel;
  Q9 T* u+ D- ~9 f        rule.process(sign);
( p& r+ s/ m6 X) r    }- v6 W3 q4 S, E! b

+ K* c. P& z/ q/ |6 m
解析:通过使用枚举类,在枚举中将 key 与 规则具体实现进行绑定。通过改变:
" S, w1 u# J- q2 f2 P/ Q
可以减少if -else使得代码更加优雅 如果需要新增渠道,我们只需要在编写具体规则实现类并继承GeneralChannelRule抽象类,并在枚举类中新增的枚举,而不需要改动到原先的任何代码。这符合了开发封闭原则。

$ V* n; ~7 N- K& x
最后

, x0 J  g% K3 P& W
以上是通过枚举来巧妙干掉if-else的方案,对于减少 if-else 还有很多有趣的解决方案(如:状态设计模式等),感兴趣的朋友去查阅相关的资料。

! }) K; U  I  i% m! i& ?+ `6 ~
赞 收藏 评论1 发布时间:2020-9-29 22:30

举报

1个回答
wavebase 回答时间:2020-9-30 09:26:20
学习了

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版