Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> ANDROID 中設計模式的采用--創建型模式

ANDROID 中設計模式的采用--創建型模式

編輯:關於Android編程



所謂模式就是在某一情景下解決某個問題的固定解決方案。

所有的創建型模式都是用作對象的創建或實例化的解決方案。

1 簡單工廠模式

創建對象的最簡單方法是使用new來創建一個對象,如果只創建一種固定不變的對象,可以使用new來創建這個對象。

如果要根據不同場景創建不同類型的對象,就可能需要采用不同的方法,就出現了不同的模式的采用和總結。

如ANDROID的媒體框架中為了實現對不同媒體源的播放,就需要實現多種播放器對象,並可能需要根據支持的媒體類型的增加,不斷添加播放器對象。

 sp p;
    switch (playerType) {
        case SONIVOX_PLAYER:
            ALOGV(" create MidiFile");
            p = new MidiFile();
            break;
        case STAGEFRIGHT_PLAYER:
            ALOGV(" create StagefrightPlayer");
            p = new StagefrightPlayer;
            break;
        case NU_PLAYER:
            ALOGV(" create NuPlayer");
            p = new NuPlayerDriver;
            break;
        case TEST_PLAYER:
            ALOGV("Create Test Player stub");
            p = new TestPlayerStub();
            break;
       case   AAH_RX_PLAYER:
            ALOGV(" create A@H RX Player");
            p = createAAH_RXPlayer();
            break;
        case  AAH_TX_PLAYER:
            ALOGV(" create A@H TX Player");
            p = createAAH_TXPlayer();
            break;
#ifdef BUILD_WITH_MST
        case MST_PLAYER:
            ALOGV(" create MstPlayer");
            p = new MstPlayer;
            break;
#endif
        default:
            ALOGE("Unknown player type: %d", playerType);
            return NULL;
    }

上面代碼可能隨著播放支持的媒體類型的添加需要不斷修改,因此為了滿足“開閉設計原則”(對修改封閉,對擴展開放),就要采用不同的模式實現媒體播放器對象的創建功能。

一種簡單的方法是把上面的代碼放到一個創建播放器的函數中,這也是ANDROID4.2以前的版本采用的模式,也稱為簡單工廠之靜態工廠模式。就如下面所示:

static sp createPlayer(player_type playerType, void* cookie,
        notify_callback_f notifyFunc)
{
  sp p;
    switch (playerType) {
        case SONIVOX_PLAYER:
            ALOGV(" create MidiFile");
            p = new MidiFile();
            break;
        case STAGEFRIGHT_PLAYER:
            ALOGV(" create StagefrightPlayer");
            p = new StagefrightPlayer;
            break;
        case NU_PLAYER:
            ALOGV(" create NuPlayer");
            p = new NuPlayerDriver;
            break;
        case TEST_PLAYER:
            ALOGV("Create Test Player stub");
            p = new TestPlayerStub();
            break;
       case   AAH_RX_PLAYER:
            ALOGV(" create A@H RX Player");
            p = createAAH_RXPlayer();
            break;
        case  AAH_TX_PLAYER:
            ALOGV(" create A@H TX Player");
            p = createAAH_TXPlayer();
            break;
#ifdef BUILD_WITH_MST
        case MST_PLAYER:
            ALOGV(" create MstPlayer");
            p = new MstPlayer;
            break;
#endif
        default:
            ALOGE("Unknown player type: %d", playerType);
            return NULL;
    }
  sp p;
    switch (playerType) {
        case SONIVOX_PLAYER:
            ALOGV(" create MidiFile");
            p = new MidiFile();
            break;
        case STAGEFRIGHT_PLAYER:
            ALOGV(" create StagefrightPlayer");
            p = new StagefrightPlayer;
            break;
        case NU_PLAYER:
            ALOGV(" create NuPlayer");
            p = new NuPlayerDriver;
            break;
        case TEST_PLAYER:
            ALOGV("Create Test Player stub");
            p = new TestPlayerStub();
            break;
       case   AAH_RX_PLAYER:
            ALOGV(" create A@H RX Player");
            p = createAAH_RXPlayer();
            break;
        case  AAH_TX_PLAYER:
            ALOGV(" create A@H TX Player");
            p = createAAH_TXPlayer();
            break;
#ifdef BUILD_WITH_MST
        case MST_PLAYER:
            ALOGV(" create MstPlayer");
            p = new MstPlayer;
            break;
#endif
        default:
            ALOGE("Unknown player type: %d", playerType);
            return NULL;
    }

當然也可以把上面的創建播放器對象的代碼放到一個工廠類中。

ANDROID系統中的PhoneFactory類就是一個簡單工廠類的采用,該類提供了makeDefaultPhones、getGsmPhone、getCdmaPhone、getDefaultPhone、makeSipPhone等工廠函數來創建和獲得不同類型的Phone對象。

以上的簡單工廠模式雖然可以在一處修改代碼,但還是不滿足“開閉設計原則”,也不滿足針對接口編程的設計原則,因此在功能擴展時還是需要修改相關代碼。

PhoneFactory工廠類還存在一個問題: 為了創建不同類型的Phone對象需要調用PhoneFactory工廠類的不同的工廠函數,雖然它們創建的Phone對象都是Phone的子類。

為了解決上面的簡單工廠模式的問題,就需要采用另外的兩個工廠模式:工廠方法和抽象工廠,一個采用了類繼承的方式,一個采用了對象組合的方式。

2 工廠模式之工廠方法

工廠方法模式通過在要創建對象的共同父類中定義一個公共抽象接口來返回具體類創建的對象,該接口返回的具體對象實際在具體類的實現公共抽象接口的創建函數中創建。

意圖:在抽象類定義一個用於創建對象的接口,讓具體類創建具體的對象。

工廠方法的UML結構類圖為:

\

在ANDROID系統的媒體路由框架中的MediaRouteProvider類就是工廠方法模式的采用。

\


抽象類MediaRouteProvider中提供了一個創建RouteController對象的公共接口onCreateRouteController,用來返回一個MediaRouteProvider.RouteController對象,MediaRouteProvider.RouteController的具體對象實際由MediaRouteProvider的具體派生類在其onCreateRouteController函數中負責創建,如MediaRouteProvider的派生類RegisteredMediaRouteProvider在其onCreateRouteController函數中創建了一個具體類型為RegisteredMediaRouteProvider.Controller的MediaRouteProvider.RouteController對象,MediaRouteProvider的間接派生類SystemMediaRouteProvider.LegacyImpl和SystemMediaRouteProvider.JellybeanImpl在各自的onCreateRouteController函數中分別創建了派生於MediaRouteProvider.RouteController的兩個具體對象:SystemMediaRouteProvider.DefaultRouteController和SystemMediaRouteProvider.SystemRouteController。


3工廠模式之抽象工廠

抽象工廠模式是通過實現一個派生於抽象工廠的具體工廠來負責創建具體的產品或產品系列。抽象工廠模式可以通過實現不同的具體工廠來創建不同的產品或系列,也可以通過具體工廠的不同方法來創建不同的產品。而用戶只與抽象工廠打交道,而不關心哪個工廠創建了具體產品。

抽象工廠模式的意圖是提供一個創建一系列相關或依賴的對象的接口,用戶可以通過該接口創建一系列相關的對象。

\



在最新版本的ANDROID系統中的媒體框架中上面的媒體播放器的創建就采用了抽象工廠模式。類圖如下:

\


其中MediaPlayerFactory為MediaPlayerFactory:IFactory的客戶,MediaPlayerFactory通過其包含的抽象工廠MediaPlayerFactory:IFactory的抽象接口createPlayer來創建不同的播放器,每種具體的播放器由每一個具體的工廠來負責創建,如StagefrightPlayer播放器由StagefrightPlayerFactory工廠創建,NuPlayerFactory工廠創建NuPlayerDriver播放器,SonivoxPlayerFactory工廠創建MidiFile播放器,TestPlayerFactory工廠創建用於測試的播放器TestPlayerStub。在MediaPlayerFactory類中每種具體的播放器工廠需要采用MediaPlayerFactory的registerFactory_l或registerFactory函數登記到MediaPlayerFactory類中,以便MediaPlayerFactory類在其工廠方法中能夠根據不同的播放類型獲得具體的播放工廠來創建具體類型的播放器。

抽象工廠與工廠方法模式的關鍵區別是:抽象工廠需要創建派生自抽象工廠的具體的工廠,通過具體工廠對象的實例方法來創建具體的產品,而工廠方法模式產品的創建是通過要創建產品的具體類中的一個類方法來完成。

4 生成器

有時對象的創建需要采用分步驟來完成,這時就可以采用生成器模式,UML類圖如下:

\

在ANDROID系統中也存在大量的生成器模式的采用。如AlertDialog、Uri、Notification等對象的創建。如下是AlertDialog對象的創建例子。

  AlertDialog dialog = new AlertDialog.Builder(mContext)
            .setTitle(r.getString(R.string.wifi_p2p_invitation_sent_title))
            .setView(textEntryView)
            .setPositiveButton(r.getString(R.string.ok), null)
            .create();

5、原形

如果需要通過克隆已有的對象來創建新的對象,就要采用原形模式。UML類圖如下:

\



在android系統中所有實現Cloneable接口的類都支持采用原形模式創建其對象,如Intent、Animation、Bundle、ComponentName、Event等對象。

如下例子為Intent對象采用原形模式創建其對象的代碼片斷:


 /**
     * Copy constructor.
     */
    public Intent(Intent o) {
        this.mAction = o.mAction;
        this.mData = o.mData;
        this.mType = o.mType;
        this.mPackage = o.mPackage;
        this.mComponent = o.mComponent;
        this.mFlags = o.mFlags;
        if (o.mCategories != null) {
            this.mCategories = new ArraySet(o.mCategories);
        }
        if (o.mExtras != null) {
            this.mExtras = new Bundle(o.mExtras);
        }
        if (o.mSourceBounds != null) {
            this.mSourceBounds = new Rect(o.mSourceBounds);
        }
        if (o.mSelector != null) {
            this.mSelector = new Intent(o.mSelector);
        }
        if (o.mClipData != null) {
            this.mClipData = new ClipData(o.mClipData);
        }
    }

    @Override
    public Object clone() {
        return new Intent(this);
    }

5單件模式

如果在一個進程中某個類只需要創建一個實例,就需要采用單件模式,類圖如下:

\

在android系統中,單件模式也普遍采用,以便維持一個進程內的某個類的唯一實例。

如許多硬件相關的系統服務管理類和服務:ServiceManager、SensorManager、WindowManagerGlobal、WallpaperManager、AccessibilityManager、UserManagerService、DownloadManager、BatteryService、ConnectivityManager等。

如下代碼采用單件模式獲得ServiceManager類的單件實例。

private static IServiceManager sServiceManager;
private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }


版權所有,請轉載時尊重版權清楚注明出處和鏈接,謝謝!



  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved