## 連載:面向對象葵花寶典:思想、技巧與實踐(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
}
}
~~~
可以看到,按照設計原則和設計模式進行重構后,原來不合理的設計逐步演變為一個優秀的設計了
- 前言
- (1) - 程序設計思想的發展
- (2) - 面向對象語言發展歷史
- (3) - 面向過程 vs 面向對象
- (4) - 面向對象是瑞士軍刀還是一把錘子?
- (5) - 面向對象迷思:面向對象導致性能下降?
- (6) - 不要說你懂“類”
- (7) - “對象”新解
- (8) - “接口” 詳解
- (9) - “抽象類” 詳解
- (10) - “抽象” 詳解
- (11) - “封裝” 詳解
- (12) - “繼承” 詳解
- (13) - “多態” 詳解
- (14) - 面向對象開發技術流程
- (15) - 需求詳解
- (16) - 需求分析終極目的
- (17) - 需求分析518方法
- (18) - 用例分析
- (19) - 功能點提取
- (20) - 用例圖的陷阱
- (21) - SSD
- (22) - 領域模型
- (23) - 領域建模三字經
- (24) - 設計模型
- (25) - 類模型
- (26) - 類模型三板斧
- (27) - 動態模型設計
- (28) - 設計原則:內聚&耦合
- (29) - 高內聚低耦合
- (30) - SRP原則
- (31) - OCP原則
- (32) - LSP原則
- (33) - ISP原則
- (34) - DIP原則
- (35) - NOP原則
- (36) - 設計原則如何用?
- (37) - 設計模式:瑞士軍刀 or 錘子?
- (38) - 設計模式之道
- (39) - 設計原則 vs 設計模式
- (40) - DECORATOR模式
- (完)- 書籍已經出版