简述
通过抽离出多个维度相互组合(聚合)来代替继承,简化系统。
话不多说,看个优化案例。
优化案例
现有系统中,对于画面窗口的边框有一套样式来控制是否有圆角。因为新的需求,需要增加两套样式,一套控制边框线条的颜色(红、黄、蓝),一套控制边框有无阴影。我们来看看几种实现方式。
最初版v0
我们看看用继承或实现的方式,会是什么样子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
| public interface Style { void style(); }
public class Radius implements style { public void style() { radius(); }
protected void radius() { System.out.println("有边框圆角"); } }
public class RadiusRed extends Radius { public void style() { super.style(); this.red(); }
protected void red() { System.out.println("红色边框"); } }
public class RadiusBlue extends Radius { public void style() { super.style(); this.blue(); }
protected void blue() { System.out.println("蓝色边框"); } }
public class RadiusYellow extends Radius { public void style() { super.style(); this.yellow(); }
protected void yellow() { System.out.println("黄色边框"); } }
public class RadiusRedShadow extends RadiusRed { public void style() { super.style(); this.shadow(); }
protected void shadow() { System.out.println("有边框阴影"); } }
public class RadiusBlueShadow extends RadiusBlue { public void style() { super.style(); this.shadow(); }
protected void shadow() { System.out.println("有边框阴影"); } }
public class RadiusYellowShadow extends RadiusYellow { public void style() { super.style(); this.shadow(); }
protected void shadow() { System.out.println("有边框阴影"); } }
public class RadiusRedNotShadow extends RadiusRed { public void style() { super.style(); this.shadow(); }
protected void shadow() { System.out.println("无边框阴影"); } }
public class RadiusBlueNotShadow extends RadiusBlue { public void style() { super.style(); this.shadow(); }
protected void shadow() { System.out.println("无边框阴影"); } }
public class RadiusYellowNotShadow extends RadiusYellow { public void style() { super.style(); this.shadow(); }
protected void shadow() { System.out.println("无边框阴影"); } }
public class NotRadius implements style { public void style() { radius(); }
protected void radius() { System.out.println("无边框圆角"); } }
public class NotRadiusRed extends NotRadius { public void style() { super.style(); this.red(); }
protected void red() { System.out.println("红色边框"); } }
public class NotRadiusBlue extends NotRadius { public void style() { super.style(); this.blue(); }
protected void blue() { System.out.println("蓝色边框"); } }
public class NotRadiusYellow extends NotRadius { public void style() { super.style(); this.yellow(); }
protected void yellow() { System.out.println("黄色边框"); } }
public class NotRadiusRedShadow extends NotRadiusRed { public void style() { super.style(); this.shadow(); }
protected void shadow() { System.out.println("边框阴影"); } }
public class NotRadiusBlueShadow extends NotRadiusBlue { public void style() { super.style(); this.shadow(); }
protected void shadow() { System.out.println("边框阴影"); } }
public class NotRadiusYellowShadow extends NotRadiusYellow { public void style() { super.style(); this.shadow(); }
protected void shadow() { System.out.println("边框阴影"); } }
public class NotRadiusRedNotShadow extends NotRadiusRed { public void style() { super.style(); this.shadow(); }
protected void shadow() { System.out.println("无边框阴影"); } }
public class NotRadiusBlueNotShadow extends NotRadiusBlue { public void style() { super.style(); this.shadow(); }
protected void shadow() { System.out.println("无边框阴影"); } }
public class NotRadiusYellowNotShadow extends NotRadiusYellow { public void style() { super.style(); this.shadow(); }
protected void shadow() { System.out.println("无边框阴影"); } }
|
可以看出,使用实现或者继承的方式来构件模块所需的类的数量及其的庞大(21个)。写吐了,太多太繁琐了。
再看看客户端的使用方法。
1 2 3 4 5 6
| public class Client { public static void main(String[] args) { Style style = new NotRadiusYellowNotShadow(); style.style(); } }
|
客户端的使用还是比较简单的,但这并不能掩盖类的数量过多的问题。
那么除了这种方法,我们还有什么别的更好的办法可以实现吗?当然有了。
修改版v1
引入桥接模式,优化多维度继承问题。
首先,我们得分析这个模块。模块中有三种不同的维度(Radius
,Color
,Shadow
),都是用来拓展Style
的。将三个维度都抽象成接口,并且将Style
定义为桥接类。我们看看新的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| public interface Radius { void radius(); }
public interface Color { void color(); }
public interface Shadow { void shadow(); }
public class HasRadius implements Radius { public void radius() { System.out.println("有边框圆角"); } }
public class HasNotRadius implements Radius { public void radius() { System.out.println("无边框圆角"); } }
public class Red implements Color { public void color() { System.out.println("红色边框"); } }
public class Yellow implements Color { public void color() { System.out.println("黄色边框"); } }
public class Blue implements Color { public void color() { System.out.println("蓝色边框"); } }
public class HasShadow implements Shadow { public void shadow() { System.out.println("有边框阴影"); } }
public class HasNotShadow implements Shadow { public void shadow() { System.out.println("无边框阴影"); } }
public class Style { private Radius radius; private Color color; private Shadow shadow;
public Style(Radius radius, Color color, Shadow shadow) { this.radius = radius; this.color = color; this.shadow = shadow; }
public void init() { radius.radius(); color.color(); shadow.shadow(); } }
|
类的数量急剧减少,而且如果三个维度中有新的Style
增加,也只需要在对应的维度增加新的实现类即可。即便增加新的维度,也只需要对应增加一套接口和实现类。最多在桥接类Style
中增加持有的接口对象即可(虽然不符合开闭原则)。
我们再来看看客户端的使用方法。
1 2 3 4 5 6
| public class Client { public static void main(String[] args) { Style style = new Style(new HasRadius(), new Red(), new HasShadow()); style.init(); } }
|
Style
持有Radius
,Color
,Shadow
,并且根据构造时传入的具体实现动态的更改持有的具体实现。易用性上也有着提升。
总结
优点
- 通过聚合或组合替代传统的继承方案。
- 提高了系统的可拓展性,每个维度增加新的是实现或者增加新的维度,对原有系统无影响。
缺点
- 增加系统的理解和设计难度,需要面向抽象编程。
- 需要预先确定正确的维度。看问题的角度不同得到的结果也不同,这个维度也是一样的,作为乙方想到的维度很有可能不是甲方预想的维度,所以这个维度的确认竟可能在功能实现前找客户确认完成之后决定。
- 增加新维度会导致需要修改桥接类,这违背了开闭原则。
适用场景
- 可以抽象出多个维度的功能组合的类设计的场景。