(39) – 设计原则 vs 设计模式
最后更新于:2022-04-01 07:30:09
## 连载:面向对象葵花宝典:思想、技巧与实践(39) - 设计原则 vs 设计模式
又是设计原则,又是设计模式,到底该用哪个呢? =============================================================================
在“设计模型”一章中,我们提到设计原则和设计模式是互补的,设计原则和设计模式互补体现在:设计原则主要用于指导“类的定义”的设计,而设计模式主要用于指导“类的行为”的设计。
举一个很简单的例子:假设我们要设计一个图形类Shape,这个类既支持三角形,又支持矩形,其代码如下:
~~~
package com.oo.designpattern.diagram;
/**
* 设计不好的Shape类,同时兼顾三角形和矩形的职责,不符合SRP设计原则
*
*/
public class BadShape {
//三角形的属性
Position a;
Position b;
Position c;
//矩形的属性
Position m;
int length;
int width;
public void drawTriangle(){
//TODO: 画出三角形
}
public void drawRectangle(){
//TODO: 画出矩形
}
}
~~~
有经验的朋友都会觉得这个设计不太合理,因为其不符合类的SRP设计原则。因此,合理的做法是将这个类按照SRP原则拆分,具体拆分方法如下:
NormalShape.java
~~~
package com.oo.designpattern.diagram;
/**
* 将BadShape拆开为三角形和矩形两个图形,并提取出NormalShape这个父类
*
*/
abstract class NormalShape {
abstract void draw();
}
~~~
NormalTriangle.java
~~~
package com.oo.designpattern.diagram;
/**
* 三角形类
*
*/
public class NormalTriangle extends NormalShape {
//三角形的属性
Position a;
Position b;
Position c;
@Override
public void draw() {
// TODO:绘画三角形
if(Config.CURRENT_SYSTEM == Config.WINDOWS){
//TODO: 调用Windows的画图方法
}
else if( Config.CURRENT_SYSTEM == Config.LINUX){
//TODO: 调用Linux的画图方法
}
else if( Config.CURRENT_SYSTEM == Config.MAC){
//TODO: 调用Mac的画图方法
}
}
}
~~~
NormalRectangle.java
~~~
package com.oo.designpattern.diagram;
/**
* 矩形类
*
*/
public class NormalRectangle extends NormalShape {
//矩形的属性
Position m;
int length;
int width;
@Override
public void draw() {
// TODO: 绘画矩形
if(Config.CURRENT_SYSTEM == Config.WINDOWS){
//TODO: 调用Windows的画图方法
}
else if( Config.CURRENT_SYSTEM == Config.LINUX){
//TODO: 调用Linux的画图方法
}
else if( Config.CURRENT_SYSTEM == Config.MAC){
//TODO: 调用Mac的画图方法
}
}
}
~~~
这样拆分之后,从类的设计原则来看,已经是符合要求了。
接下来我们再使用设计模式来继续完善这个设计,这里就需要使用设计模式之道来指导我们设计了,即:**找到变化,封装变化**。
关于图形类一个比较明显的变化是跨平台,比如说要同时支持Windows、Linux、Mac三个桌面操作系统,那么实际画图的方法和需要调用的函数可能就随着平台的不同而变化,因此我们要找出一种方法来封装这种变化。
参考《设计模式》,可以知道这种方法就是“Bridge模式”,使用了Bridge后,会多出几个接口和实现类。
具体实现如下:
GoodShape.java
~~~
package com.oo.designpattern.diagram;
/**
* 在NormalShape的基础上,增加Bridge设计模式的实现,使其更加适应于跨平台
*
*/
abstract public class GoodShape {
protected ShapeDraw _draw; //将不同平台的实现封装到一个新的接口ShapeDraw
abstract void draw();
}
~~~
GoodTriangle.java
~~~
package com.oo.designpattern.diagram;
/**
* 按照Bridge设计模式设计的三角形类
*
*/
public class GoodTriangle extends GoodShape {
GoodTriangle(ShapeDraw draw){
this._draw = draw;
}
@Override
void draw() {
// TODO Auto-generated method stub
this._draw.drawTriangle();
}
}
~~~
GoodRectangle.java
~~~
package com.oo.designpattern.diagram;
/**
* 按照Bridge设计模式设计的矩形类
*
*/
public class GoodRectangle extends GoodShape {
GoodRectangle(ShapeDraw draw){
this._draw = draw;
}
@Override
void draw() {
// TODO Auto-generated method stub
this._draw.drawRectangle();
}
}
~~~
ShapeDraw.java
~~~
package com.oo.designpattern.diagram;
/**
* 按照Bridge设计模式进行设计的画图的接口,封装了跨平台不同的实现
*
*/
interface ShapeDraw {
public void drawTriangle();
public void drawRectangle();
}
~~~
WindowsDraw.java
~~~
package com.oo.designpattern.diagram;
/**
* Windwos上的画图实现
*
*/
public class WindowsDraw implements ShapeDraw {
@Override
public void drawTriangle() {
// TODO Auto-generated method stub
}
@Override
public void drawRectangle() {
// TODO Auto-generated method stub
}
}
~~~
LinuxDraw.java
~~~
package com.oo.designpattern.diagram;
/**
* Linux上的画图实现
*
*/
public class LinuxDraw implements ShapeDraw {
@Override
public void drawTriangle() {
// TODO Auto-generated method stub
}
@Override
public void drawRectangle() {
// TODO Auto-generated method stub
}
}
~~~
MacDraw.java
~~~
package com.oo.designpattern.diagram;
/**
* Mac上的画图实现
*
*/
public class MacDraw implements ShapeDraw {
@Override
public void drawTriangle() {
// TODO Auto-generated method stub
}
@Override
public void drawRectangle() {
// TODO Auto-generated method stub
}
}
~~~
可以看到,按照设计原则和设计模式进行重构后,原来不合理的设计逐步演变为一个优秀的设计了