建立對象的最簡單方法是使用new來建立一個對象,假設僅僅建立一種固定不變的對象,能夠使用new來建立這個對象。
假設要依據不同情境建立不同類型的對象,就可能須要採用不同的方法,就出現了不同的模式的採用和總結。
如ANDROID的媒體架構中為了實現對不同媒體源的播放,就須要實現多種播放器對象,並可能須要依據支援的媒體類型的添加,不斷加入播放器對象。
sp<MediaPlayerBase> 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 [email protected] RX Player"); p = createAAH_RXPlayer(); break; case AAH_TX_PLAYER: ALOGV(" create [email protected] 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<MediaPlayerBase> createPlayer(player_type playerType, void* cookie, notify_callback_f notifyFunc){ sp<MediaPlayerBase> 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 [email protected] RX Player"); p = createAAH_RXPlayer(); break; case AAH_TX_PLAYER: ALOGV(" create [email protected] 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<MediaPlayerBase> 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 [email protected] RX Player"); p = createAAH_RXPlayer(); break; case AAH_TX_PLAYER: ALOGV(" create [email protected] 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的子類。
為瞭解決上面的簡單原廠模式的問題。就須要採用另外的兩個原廠模式:Factory 方法和抽象工廠,一個採用了類繼承的方式,一個採用了對象組合的方式。
2 原廠模式之Factory 方法
Factory 方法模式通過在要建立對象的共同父類中定義一個公用抽象介面來返回詳細類建立的對象。該介面返回的詳細對象實際在詳細類的實現公用抽象介面的建立函數中建立。
意圖:在抽象類別定義一個用於建立對象的介面。讓詳細類建立詳細的對象。
Factory 方法的UML結構類圖為:
在ANDROID系統的媒體路由架構中的MediaRouteProvider類就是Factory 方法模式的採用。
抽象類別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原廠模式之抽象工廠
抽象原廠模式是通過實現一個派生於抽象工廠的詳細工廠來負責建立詳細的產品或產品系列。抽象原廠模式能夠通過實現不同的詳細工廠來建立不同的產品或系列,也能夠通過詳細工廠的不同方法來建立不同的產品。而使用者僅僅與抽象工廠打交道。而不關心哪個工廠建立了詳細產品。
抽象原廠模式的意圖是提供一個建立一系列相關或依賴的對象的介面,使用者能夠通過該介面建立一系列相關的對象。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvR29vSG9uZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center">
在最新版本號碼的ANDROID系統中的媒體架構中上面的媒體播放器的建立就採用了抽象原廠模式。
類圖例如以下:
當中MediaPlayerFactory為MediaPlayerFactory:IFactory的客戶。MediaPlayerFactory通過其包括的抽象工廠MediaPlayerFactory:IFactory的抽象介面createPlayer來建立不同的播放器。每種詳細的播放器由每個詳細的工廠來負責建立。如StagefrightPlayer播放器由StagefrightPlayerFactory工廠建立,NuPlayerFactory工廠建立NuPlayerDriver播放器。SonivoxPlayerFactory工廠建立MidiFile播放器。TestPlayerFactory工廠建立用於測試的播放器TestPlayerStub。在MediaPlayerFactory類中每種詳細的播放器工廠須要採用MediaPlayerFactory的registerFactory_l或registerFactory函數登記到MediaPlayerFactory類中。以便MediaPlayerFactory類在其Factory 方法中可以依據不同的播放類型獲得詳細的播放工廠來建立詳細類型的播放器。
抽象工廠與Factory 方法模式的關鍵差別是:抽象工廠須要建立派生自抽象工廠的詳細的工廠。通過詳細工廠對象的執行個體方法來建立詳細的產品,工廠對象的責任就是建立詳細的產品;而Factory 方法模式是提供一個架構,產品的建立是通過要建立產品的子類中的一個Factory 方法來完畢,建立產品僅僅是子類的諸多責任中的一項任務。
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<String>(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); }
6 單件模式
假設在一個進程中某個類僅僅須要建立一個執行個體,就須要採用單件模式,類圖例如以下:
在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; }
著作權全部。請轉載時尊重著作權清楚註明出處和連結,謝謝!