ANDROID 中设计模式的采用--创建型模式



        所谓模式就是在某一情景下解决某个问题的固定解决方案。

        所有的创建型模式都是用作对象的创建或实例化的解决方案。

        1 简单工厂模式

创建对象的最简单方法是使用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 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<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 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<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 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类就是一个简单工厂类的采用,该类提供了makeDefaultPhonesgetGsmPhonegetCdmaPhonegetDefaultPhonemakeSipPhone等工厂函数来创建和获得不同类型的Phone对象。

以上的简单工厂模式虽然可以在一处修改代码,但还是不满足“开闭设计原则”,也不满足针对接口编程的设计原则,因此在功能扩展时还是需要修改相关代码。

PhoneFactory工厂类还存在一个问题: 为了创建不同类型的Phone对象需要调用PhoneFactory工厂类的不同的工厂函数,虽然它们创建的Phone对象都是Phone的子类。

为了解决上面的简单工厂模式的问题,就需要采用另外的两个工厂模式:工厂方法和抽象工厂,一个采用了类继承的方式,一个采用了对象组合的方式。

2 工厂模式之工厂方法

工厂方法模式通过在要创建对象的共同父类中定义一个公共抽象接口来返回具体类创建的对象,该接口返回的具体对象实际在具体类的实现公共抽象接口的创建函数中创建。

 意图:在抽象类定义一个用于创建对象的接口,让具体类创建具体的对象。

工厂方法的UML结构类图为:


ANDROID系统的媒体路由框架中的MediaRouteProvider类就是工厂方法模式的采用。


抽象类MediaRouteProvider中提供了一个创建RouteController对象的公共接口onCreateRouteController,用来返回一个MediaRouteProvider.RouteController对象,MediaRouteProvider.RouteController的具体对象实际由MediaRouteProvider的具体派生类在其onCreateRouteController函数中负责创建,如MediaRouteProvider的派生类RegisteredMediaRouteProvider在其onCreateRouteController函数中创建了一个具体类型为RegisteredMediaRouteProvider.ControllerMediaRouteProvider.RouteController对象,MediaRouteProvider的间接派生类SystemMediaRouteProvider.LegacyImplSystemMediaRouteProvider.JellybeanImpl在各自的onCreateRouteController函数中分别创建了派生于MediaRouteProvider.RouteController的两个具体对象:SystemMediaRouteProvider.DefaultRouteControllerSystemMediaRouteProvider.SystemRouteController


3工厂模式之抽象工厂

抽象工厂模式是通过实现一个派生于抽象工厂的具体工厂来负责创建具体的产品或产品系列。抽象工厂模式可以通过实现不同的具体工厂来创建不同的产品或系列,也可以通过具体工厂的不同方法来创建不同的产品。而用户只与抽象工厂打交道,而不关心哪个工厂创建了具体产品。

抽象工厂模式的意图是提供一个创建一系列相关或依赖的对象的接口,用户可以通过该接口创建一系列相关的对象。



在最新版本的ANDROID系统中的媒体框架中上面的媒体播放器的创建就采用了抽象工厂模式。类图如下:


其中MediaPlayerFactoryMediaPlayerFactory:IFactory的客户,MediaPlayerFactory通过其包含的抽象工厂MediaPlayerFactory:IFactory的抽象接口createPlayer来创建不同的播放器,每种具体的播放器由每一个具体的工厂来负责创建,如StagefrightPlayer播放器由StagefrightPlayerFactory工厂创建,NuPlayerFactory工厂创建NuPlayerDriver播放器,SonivoxPlayerFactory工厂创建MidiFile播放器,TestPlayerFactory工厂创建用于测试的播放器TestPlayerStub。在MediaPlayerFactory类中每种具体的播放器工厂需要采用MediaPlayerFactoryregisterFactory_lregisterFactory函数登记到MediaPlayerFactory类中,以便MediaPlayerFactory类在其工厂方法中能够根据不同的播放类型获得具体的播放工厂来创建具体类型的播放器。

抽象工厂与工厂方法模式的关键区别是:抽象工厂需要创建派生自抽象工厂的具体的工厂,通过具体工厂对象的实例方法来创建具体的产品,而工厂方法模式产品的创建是通过要创建产品的具体类中的一个类方法来完成。

生成器

有时对象的创建需要采用分步骤来完成,这时就可以采用生成器模式,UML类图如下:

ANDROID系统中也存在大量的生成器模式的采用。如AlertDialogUriNotification等对象的创建。如下是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接口的类都支持采用原形模式创建其对象,如IntentAnimationBundleComponentNameEvent等对象。

如下例子为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);
    }

5单件模式

如果在一个进程中某个类只需要创建一个实例,就需要采用单件模式,类图如下:

android系统中,单件模式也普遍采用,以便维持一个进程内的某个类的唯一实例。

如许多硬件相关的系统服务管理类和服务:ServiceManagerSensorManagerWindowManagerGlobalWallpaperManagerAccessibilityManagerUserManagerServiceDownloadManagerBatteryServiceConnectivityManager等。

如下代码采用单件模式获得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;
    }


                                      版权所有,请转载时尊重版权清楚注明出处和链接,谢谢!




郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。