(点击
上方公众号
,可快速关注)
来源:伯乐在线专栏作者 - 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
;
}
}
使用场景
在以下情况下可以考虑使用简单工厂模式:
-
工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
-
客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
优点
缺点
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