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

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

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类就是一个简单工厂类的采用,该类提供了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<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;
}

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



ANDROID 中设计模式的采用--创建型模式的更多相关文章

  1. NET设计模式 第二部分 创建型模式(6):创建型模式专题总结(Creational Pattern)

    创建型模式专题总结(Creational Pattern) ——.NET设计模式系列之七 Terrylee,2006年1月 概述 创建型模式,就是用来创建对象的模式,抽象了实例化的过程.它帮助一个系统 ...

  2. 抽象工厂模式(abstract)创建型模式

    (一)简单工厂模式? 现在的学习是面向对象面向接口的,但是执行时的操作需要实例化后的对象.随着我们需要的类的增加,我们就需要把这些共同的东西提取出来,放在一个抽象类中,让这些子类来继承抽象类.当我们调 ...

  3. 设计模式学习之建造者模式(Builder,创建型模式)(6)

    假如我们需要建造一个房子,并且我们也不知道如何去建造房子,所以就去找别人帮我们造房子 第一步: 新建一个房子类House,里面有房子该有的属性,我们去找房子建造者接口HouseBuilder,我们要建 ...

  4. 设计模式学习之原型模式(Prototype,创建型模式)(5)

    通过序列化的方式实现深拷贝 [Serializable] public class Person:ICloneable { public string Name { get; set; } publi ...

  5. 设计模式-抽象工厂模式(AbstractFactory)(创建型模式)

    //以下代码来源: 设计模式精解-GoF 23种设计模式解析附C++实现源码 //Product.h #pragma once class AbstractProductA { public: vir ...

  6. Java 23种设计模式详尽分析与实例解析之一--创建型模式

    面向对象的设计原则 常用的面向对象设计原则包括7个,这些原则并不是独立存在的,它们相互依赖.互为补充. Java设计模式 创建型模式 简单工厂模式 模式动机: 考虑一个简单的软件应用场景,一个软件系统 ...

  7. 设计模式GOF23(创建型模式)

    • 创建型模式:  单例模式.工厂模式.抽象工厂模式.建造者模式.原型模式.   • 结构型模式: –适配器模式.桥接模式.装饰模式.组合模式.外观模式.享元模式.代理模式.   • 行为型模式: 模 ...

  8. 第26章 创建型模式大PK

    26.1 工厂方法模式 VS 建造者模式 26.1.1 按工厂方法建造超人 (1)产品:两类超人,成年超人和未成年超人. (2)工厂:这里选择简单工厂 [编程实验]工厂方法建造超人 //创建型模式大P ...

  9. .NET设计模式(7):创建型模式专题总结(Creational Pattern)(转)

    概述 创建型模式,就是用来创建对象的模式,抽象了实例化的过程.它帮助一个系统独立于如何创建.组合和表示它的那些对象.本文对五种常用创建型模式进行了比较,通过一个游戏开发场景的例子来说该如何使用创建型模 ...

随机推荐

  1. cocos2dx 3.2之Lua打飞机项目

    1          创建lua打飞机项目 cocos new T32Lua -dE:\Installed\cocos2d-x-3.2\cocos2d-x-3.2\projects -l lua 2 ...

  2. 在O(1)时间内删除单链表结点

    给定单链表的一个结点的指针,同时该结点不是尾结点,此外没有指向其它任何结点的指针,请在O(1)时间内删除该结点. int deleteNode(LNode **head, LNode **node) ...

  3. 剑指Offer——全排列递归思路

    剑指Offer--全排列递归思路 前言 全排列,full permutation, 可以利用二叉树的遍历实现.二叉树的递归遍历,前中后都简洁的难以置信,但是都有一个共同特点,那就是一个函数里包含两次自 ...

  4. Hibernate超简单多表操作

    所谓一对多映射 在数据库中我们通常会通过添加外键的方式将表关联起来,表现一对多的关系. 而在Hibernate中,我们则要通过在一方持有多方的集合来实现,即在"一"的一端中使用元素 ...

  5. android6.0SDK 删除HttpClient的相关类的解决方法

    本文转载自博客:http://blog.csdn.net/yangqingqo/article/details/48214865 android6.0SDK中删除HttpClient的相关类的解决方法 ...

  6. 【一天一道LeetCode】#342. Power of Four

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  7. hive的数据导入与数据导出:(本地,云hdfs,hbase),列分隔符的设置,以及hdfs上传给pig如何处理

    hive表的数据源有四种: hbase hdfs 本地 其他hive表 而hive表本身有两种: 内部表和外部表. 而hbase的数据在hive中,可以建立对应的外部表(参看hive和hbase整合) ...

  8. CUDA command Profiler

    这里我不使用默认设置: timestamp gpustarttimestamp gpuendtimestamp gridsize threadblocksize dynsmemperblock sta ...

  9. 网站开发进阶(三十七)JSP页面跳转问题解决

    JSP页面跳转问题解决 PS:本篇博文质量欠佳,仅供个人学习之用. 前言 在做Web开发时,对别人的应用(jsp+servlet)进行服务器部署时出现了页面跳转无效的情况.但是项目在本地未出现此状况. ...

  10. ROS_Kinetic_07 ROS中机器人三维物理引擎高保真仿真利器gazebo 7.0

    ROS_Kinetic_07 ROS中机器人三维物理引擎高保真仿真利器gazebo 7.0 ROS kinetic中的gazebo版本是7.0,有很多新的特性. 首先,启动gazebo: ~$ gaz ...