专栏名称: 安卓开发精选
伯乐在线旗下账号,分享安卓应用相关内容,包括:安卓应用开发、设计和动态等。
目录
相关文章推荐
郭霖  ·  你所不知道的Android ... ·  2 天前  
开发者全社区  ·  昔日同学中的三好学生都翻车了 ·  22 小时前  
开发者全社区  ·  星星眼小笼包女星离婚的内幕 ·  昨天  
开发者全社区  ·  币圈大瓜! ·  2 天前  
开发者全社区  ·  计算机开始跌落神坛,想不到这么差... ·  2 天前  
51好读  ›  专栏  ›  安卓开发精选

Android 源码中的静态工厂方法

安卓开发精选  · 公众号  · android  · 2016-10-05 10:16

正文

(点击 上方公众号 ,可快速关注)


来源:伯乐在线专栏作者 - PleaseCallMeCoder

链接:http://android.jobbole.com/84838/

点击 → 了解如何加入专栏作者


我们知道工厂模式有三兄弟,通常我们说的工厂模式指的是工厂方法模式,它的应用频率最高。本篇博客分享的简单工厂模式是工厂方法模式的“小弟”,确切的来讲它不属于设计模式,而是一种方法。此外,工厂方法模式还有一位“大哥”——抽象工厂模式。


今天我们来分享一下简单工厂模式的一些情况,以及它在Android源码中的应用。


简单工厂模式


定义


简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。


结构



简单工厂模式所涉及到的角色:


  • Product(抽象产品角色) :产品的通用接口,定义产品的行为。

  • ConcreteProduct(具体产品角色) :具体产品类,实现了Product接口。

  • Creator(工厂角色):工厂类 ,通过静态工厂方法factoryMethord来创建对象。


实现


抽象产品角色


abstract class Product {

//所有产品类的公共业务方法

public void methodSame () {

//公共方法的实现

}

//声明抽象业务方法

public abstract void methodDiff ();

}


具体产品角色


class ConcreteProduct extends Product {

//实现业务方法

public void methodDiff () {

//业务方法的实现

}

}


工厂角色


class Creator {

//静态工厂方法

public static Product getProduct ( String arg ) {

Product product = null ;

if ( arg . equalsIgnoreCase ( "A" )) {

product = new ConcreteProductA ();

//初始化设置product

}

else if ( arg . equalsIgnoreCase ( "B" )) {

product = new ConcreteProductB ();

//初始化设置product

}

return product ;

}

}


使用场景


在以下情况下可以考虑使用简单工厂模式:


  1. 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。

  2. 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。


优点


  • 工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离。

  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。


缺点


  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。

  • 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。


Android中简单工厂模式的应用


在Android中我们了解的使用到了简单工厂方法的地方有Bitmap对象的获取、Fragment创建等。接下来我们分开看一下。


Bitmap源码分析


首先来说我们是不能通过new方法来创建Bitmap对象的,因为Bitmap类的构造函数是私有的,只能是通过JNI实例化。


接下来我们随便找个入口开始看,比如:


Bitmap bmp = BitmapFactory . decodeFile ( String pathName );


我们把源码中的调用关系找出来,如下


public static Bitmap decodeFile ( String pathName ) {

return decodeFile ( pathName , null );

}

public static Bitmap decodeFile ( String pathName , Options opts ) {

Bitmap bm = null ;

InputStream stream = null ;

try {

stream = new FileInputStream ( pathName );

bm = decodeStream ( stream , null , opts );

} catch ( Exception e ) {

/*  do nothing.

If the exception happened on open, bm will be null.

*/

Log . e ( "BitmapFactory" , "Unable to decode stream: " + e );

} finally {

if ( stream != null ) {

try {

stream . close ();

} catch ( IOException e ) {

// do nothing here

}

}

}

return bm ;

}

public static Bitmap decodeStream ( InputStream is , Rect outPadding , Options opts ) {

// we don't throw in this case, thus allowing the caller to only check

// the cache, and not force the image to be decoded.

if ( is == null ) {

return null ;

}

Bitmap bm = null ;

Trace . traceBegin ( Trace . TRACE_TAG_GRAPHICS , "decodeBitmap" );

try {

if ( is instanceof AssetManager . AssetInputStream ) {

final long asset = (( AssetManager . AssetInputStream ) is ). getNativeAsset ();

bm = nativeDecodeAsset ( asset , outPadding , opts );

} else {

bm = decodeStreamInternal ( is , outPadding , opts );

}

if ( bm == null && opts != null && opts . inBitmap != null ) {

throw new IllegalArgumentException ( "Problem decoding into existing bitmap" );

}

setDensityFromOptions ( bm , opts );

} finally {

Trace . traceEnd ( Trace . TRACE_TAG_GRAPHICS );

}

return bm ;

}

private static native Bitmap nativeDecodeStream ( InputStream is , byte [] storage ,

Rect padding , Options opts );

/**

* Set the newly decoded bitmap's density based on the Options.

*/

private static void setDensityFromOptions ( Bitmap outputBitmap , Options opts ) {

if ( outputBitmap == null || opts == null ) return ;

final int density = opts . inDensity ;

if







请到「今天看啥」查看全文