可擴展性系統設計的思考

在 面向對象剖析 和 設計模式剖析 兩篇文章中提到面向對象設計是解決複雜系統架構設計有效方法,因為面向對象是模擬人類的思維去發現對象和對象之間的關聯,並且通過面向對象的技術去實現系統的可擴展性。設計模式的核心是面向對象,它把面向對象的三大特性:封閉、繼承、多態,運用得爐火純青,總結出常用的23種設計模式。

找到變化 封裝變化

這是設計模式中,大師提出的一句高度凝練的話,可以說設計模式所做的事情都是圍繞它來講,把它講清楚了,基本上設計模式也就掌握得差不多。有兩個問題隨之出現了:如何找到變化、如何封裝變化呢?

對於"如何找到變化"這個問題,是依靠人主動地思考,這個業務點在未來有沒有可能變化,如果有可能變化,就要想到一個好的設計方式去設計它。

那"如何去封裝變化"呢?找到了這個變化,就要把它"封裝"起來,封裝的意思是對外是透明的,只要按照這個規則做就行,剩下的內容就是討論如何封裝變化。

封裝變化

封裝的手段有多種,但從本質上來講,它的原理就是佔位符思想。告訴這裡是可以變化的,你按照這個規則來做就行了。

變數--最簡單的封裝變化

最簡單的封裝變化的手段就是變數,比如文案、站內信、簡訊、配置,這些都是不能寫死的,後面都有可能是變化的。既然這個變化已經找到,那就封裝它唄,用一個變數來代替,每次程序都讀這個變數,這個變數存儲的地方有很多方法:如資料庫、Memcache、Redis等等。

介面--基礎的封裝變化

提到設計模式,最常用的兩個原則就是"開閉原則"、"面向抽象設計,不依賴於具體的實現",所以一般是先定義一個介面,然後實現類就可以無限擴展,在引用的時候是依賴於介面(抽象)。這是最基礎的封裝變化的手段。

比如策略模式:

interface Strategy{

public void doBussice();

}

public class StrategyContext{

private Strategy strategy;

public StrategyContext(Strategy strategy){

this.strategy = strategy

}

public void doBussice(){

strategy.doBussice();

}

}

這種模式具有通用性,它的思想是類中引用一個介面,至於介面的實現是什麼我不關心,實現這個介面就可以達到可擴展性。像適配器、代理,雖然它們解決問題不同,但本質做法是一樣的。

這裡有兩個點:一個是對象類型轉換(子類轉換成父類),另一個是多態(面向介面編程)。用這種基本的方法是能解決一部分問題,至少可以做到"開閉原則"、"面向抽象編程",但有時這種模式可引起類爆炸,實現的類太多了,不好控制。

繼承--另一種基礎的封裝變化

除了介面可以實現可擴展性,還有另外一種方法可以實現,那就是繼承,繼承有兩種功能:一個是重用性;另一個是可修改父類特性。正由於繼承子類可以修改父類的特性(是不是可擴展呢?),所以有了到底是用介面還是繼承之爭。有人贊同用介面,不喜歡用繼承,認為繼承有"破壞"的作用在裡面。

比如模板模式:

abstract class template{

abstract void printHeader();

abstract void printBody();

abstract void printFooter();

public void print(){

printHeader();

printBody();

printFooter();

}

}

public class templateImplA extends template{

public void printHeader(){

。。。

}

public void printBody(){

。。。

}

public void printFooter(){

。。。

}

}

這樣,可以實現多個子類來達到可擴展性。

介面+繼承--一種高級的封裝變化

上面提到了介面和繼承有過之爭,它們並不是水火不相容的,介面是一種標準,繼承有兩重作用(重用性+可擴展性)。在抽象類中是可以引入介面類,然後在子類中可以重寫這個介面來達到增加功能的特性,裝修模式就是一個典型的例子。

interface Human(){

public void eat();

}

BasicPerson implements Human{

public void eat(){

。。。

}

}

abstract class Decorate implements Human{

private Human human;

public Decorate(Human human){

this.human = human;

}

public void eat() {

human.eat();

}

}

public class DecorateImpOne extends Decorate {

public DecorateImpOne(Human human) {

super(human);

}

@Override

public void eat() {

super.eat();

addFunction1();

}

private void addFunction1(){

System.out.println("go KTV ....");

}

}

如果你還想增加功能,還可以繼承Decorate去實現更多的子類。

實戰

顧客點餐。

分析:拿到這個需求時,先分析它裡面包含了哪些對象,然後分析這些對象之間的關係是什麼。

對象:顧客、服務員、廚師、命令(菜單)

關聯關係:服務員接收顧客的命令,因此服務員與命令的關聯是包含關係

廚師與命令,廚師是命令的執行者,它們之間是一種包含關係。

interface Command{

void execute();

}

public class DoFoodCommand implements Command{

private Chef chef;

public DoFoodCommand(Chef chef){

this.chef = chef;

}

public void execute(){

chef.doCook();

}

}

public class Waiter{

private Command command;

public Waiter(Command command){

this.command = command;

}

public void execute(){

if(command != null){

command.execute();

}

}

}


推薦閱讀:

單例模式小結
類的設計原則
面向新手的雜談:Flyweight(續)
設計模式之「Decorator」註疏#02

TAG:設計模式 | 軟體架構 |