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

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

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. Xcode无法安装基于ruby的插件问题的解决

    Xcode有时需要安装一些第三方插件,很多插件是基于ruby的,确切的说是基于ruby gem的! 但是在国内有一个很尴尬的情况,就是官方的gems网站:https://rubygems.org 的安 ...

  2. JAVA面向对象-----接口的概述

    接口的概述 **接口(interface):**usb接口,主要是使用来拓展笔记本的功能,那么在java中的接口主要是使用来拓展定义类的功能,可以弥补java中单继承的缺点. class Pencil ...

  3. Android事件分发回传机制

    转载本博客,请注明出处:点击打开链接   http://blog.csdn.net/qq_32059827/article/details/52489026 之前以一个爷爷给孙子分馒头的故事,初探了安 ...

  4. [openwrt] uci 的shell和lua接口

    uci是openwrt上配置操作的接口,不管是自动化的shell脚本,还是使用luci来二次开发配置界面,都会用到这部分知识. uci提供了lua, shell, c接口,这里主要用到了前两种 she ...

  5. python使用qq服务器发送邮件

    python使用qq服务器发送邮件 直接上代码: #!/usr/bin/python2.7 #-*- coding: UTF-8 -*- # sendmail.py # # init created: ...

  6. RecyclerView嵌套RecyclerView

    ListView嵌套GridView http://blog.csdn.net/baiyuliang2013/article/details/42646289 RecyclerView下拉刷新上拉加载 ...

  7. SSH深度历险(三) EJB Session Bean有状态和无状态的区别与联系

    刚开始对两种sessionbean存在误解,认为有状态是实例一直存在,保存每次调用后的状态,并对下一次调用起作用,而认为无状态是每次调用实例化一次,不保留用户信息.仔细分析并用实践检验后,会发现,事实 ...

  8. 匿名内部类使用外面的类为什么要用final型

    从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方法内部(可出现在形式参数定义处或者方法体处),因而访问方法中的局部变量(形式参数或局部变量)是天经地义的.是很自然的 为 ...

  9. DB Query Analyzer 6.04 is distributed, 78 articles concerned have been published

        DB Query Analyzer 6.04 is distributed,78 articles concerned have been published  DB Query Analyz ...

  10. android:layout_gravity和gravity的区别

    文章转自http://blog.csdn.net/shakespeare001/article/details/784346,给出了很详细的解释. 1.首先来看看Android:layout_grav ...