Android原始碼中的靜態工廠方法
我們知道工廠模式有三兄弟,通常我們說的工廠模式指的是工廠方法模式,它的應用頻率最高。本篇部落格分享的簡單工廠模式是工廠方法模式的“小弟”,確切的來講它不屬於設計模式,而是一種方法。此外,工廠方法模式還有一位“大哥”——抽象工廠模式。
今天我們來分享一下簡單工廠模式的一些情況,以及它在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 (density != 0) {
outputBitmap.setDensity(density);
final int targetDensity = opts.inTargetDensity;
if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
return;
}
byte[] np = outputBitmap.getNinePatchChunk();
final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
if (opts.inScaled || isNinePatch) {
outputBitmap.setDensity(targetDensity);
}
} else if (opts.inBitmap != null) {
// bitmap was reused, ensure density is reset
outputBitmap.setDensity(Bitmap.getDefaultDensity());
}
}
我們來分析一下呼叫過程,可以看到decodeFile(String pathName)呼叫的是decodeFile(String pathName, Options opts),在兩個引數的decodeFile方法中又去呼叫了decodeStream(InputStream is, Rect outPadding, Options opts)方法,然後最終呼叫nativeDecodeAsset或者nativeDecodeStream來構建Bitmap物件,這兩個都是native方法(Android中使用Skia庫來解析影象 )。再經過setDensityFromOptions方法的一些設定解碼密度之類的操作,返回我們要的Bitmap物件。
/**
* Creates Bitmap objects from various sources, including files, streams, and byte-arrays.
*/
看下BitmapFactory的註釋我們可以看到,這個工廠支援從不同的資源建立Bitmap物件,包括files, streams, 和byte-arrays,但是呼叫關係都大同小異。
Fragment建立
有時候,為了簡化簡單工廠模式,我們可以將抽象產品類和工廠類合併,將靜態工廠方法移至抽象產品類中。Fragment的建立使用簡單工廠方法沒有抽象產品類,所以工廠類放到了實現產品類中。
在AndroidStudio中輸入newInstance會自動補全Fragment的簡單工廠方法。
public static TasksFragment newInstance() {
Bundle args = new Bundle();
TasksFragment fragment = new TasksFragment();
fragment.setArguments(args);
return fragment;
}
使用靜態工廠方法,將外部傳入的引數可以通過Fragment.setArgument儲存在它自己身上,這樣我們可以在Fragment.onCreate(…)呼叫的時候將這些引數取出來。
這樣寫有什麼好處呢?
避免了在建立Fragment的時候無法在類外部知道所需引數的問題。
Fragment推薦使用setArguments來傳遞引數,避免在橫豎屏切換的時候Fragment自動呼叫自己的無參建構函式,導致資料丟失。
相關推薦
Android原始碼中的靜態工廠方法
我們知道工廠模式有三兄弟,通常我們說的工廠模式指的是工廠方法模式,它的應用頻率最高。本篇部落格分享的簡單工廠模式是工廠方法模式的“小弟”,確切的來講它不屬於設計模式,而是一種方法。此外,工廠方法模式還有一位“大哥”——抽象工廠模式。 今天我們來分享一下簡單工廠
Android之大話設計模式--簡單工廠模式(靜態工廠方法模式)
簡單工廠模式解釋: 簡單工廠模式(Simple Factory Pattern)屬於類的創新型模式,又叫靜態工廠方法模式(Static Factory Method Pattern),是通過專門定義一個類來負責建立其他類的例項,被建立的例項通常都具有相同的父親。 UML圖:
【代碼優化】考慮使用靜態工廠方法取代構造器
ava tracking 什麽事 依據 mod true data -m span 靜態工廠方法與設計模式中的工廠方法模式不同,和設計模式中的工廠方法模式不直接相應。 使用靜態工廠方法比構造器的優勢: 第一、靜態工廠方法是有名稱的,而構造器是通過
EffectiveJava讀書筆記——考慮用靜態工廠方法代替構造器(一)
無法 父類 應該 樹結構 對象 如何 log 筆記 工廠類 參考網址:http://blog.csdn.net/mingyunduoshou/article/details/6149758 http:[email protect
靜態工廠方法+服務提供者框架模板
tro class return sse strong ava hash [] nes Provider.java public interface Provider { Service newService(); } Service.java public in
實例/靜態工廠方法得到bean
create spa tor bean .config return col pan creat <bean id="a" class="com.yundaex.wms.config.TestBeanChild" /> <bean id="b
用靜態工廠方法代替構造器、遇到多個構造器參數時要考慮用構建器
泛型 不用 推斷 frame public 多參數 eof ram api 一、用靜態工廠方法代替構造器 類通過共有的構造方法可以提供很大的優點:1、構造方法可一有不同的名字,我們可以通過名字區分構造什麽樣子的對象,而構造器名字相同,當參數列表的數目相同 順序不同時 很大的
JavaScript中的工廠方法、構造函數與class
格式 ret 存在 mon pillar bug 多種方法 希望 journal JavaScript中的工廠方法、構造函數與class 本文轉載自:眾成翻譯 譯者:謝於中 鏈接:http://www.zcfy.cc/article/1129 原文:https://med
Effective Java 第三版——1. 考慮使用靜態工廠方法替代構造方法
plain 額外 body image 單獨 oba car 翻譯 一個 Tips 《Effective Java, Third Edition》一書英文版已經出版,這本書的第二版想必很多人都讀過,號稱Java四大名著之一,不過第二版2009年出版,到現在已經將近8年的時
【Effective Java讀書筆記】創建和銷毀對象(一):考慮使用靜態工廠方法代替構造器
返回對象 boolean 簡化 將不 其他 種類型 bigint color pre 類可以提供一個靜態方法,返回類的一個靜態實例,如Boolean包裝類的一個獲取實例的靜態方法 1 public static Boolean valueOf(boolean b) { 2
Spring(十三):使用工廠方法來配置Bean的兩種方式(靜態工廠方法&實例工廠方法)
color 示例 簡單的 rgs icc tostring pac ng- clas 通過調用靜態工廠方法創建Bean 1)調用靜態工廠方法創建Bean是將對象創建的過程封裝到靜態方法中。當客戶端需要對象時,只需要簡單地調用靜態方法,而不需要關心創建對象的具體細節。 2
一、考慮使用靜態工廠方法替代構造函數
fault 變化 擁有 def enum 可選 不能 鼓勵 ice 1、何為靜態工廠方法 靜態工廠方法就是一個返回類實例的靜態方法。比如Boolean的valueof方法: 1 public static final Boolean TRUE = new Boolea
Java物件學習之建立物件——使用靜態工廠方法代替構造器缺點
最近學習Android知識,發現Java好多的基礎知識運用的真的很一般,所以決定在重新梳理一下,現在Kotlin也來了,在Android之路上,留給我看Java的時間不多了。 靜態我們就來簡單介紹一下,使用靜態工廠方法建立物件相較於構造器建立的物件的優缺
Java物件學習之建立物件——使用靜態工廠方法代替構造器優點(四)
最近學習Android知識,發現Java好多的基礎知識運用的真的很一般,所以決定在重新梳理一下,現在Kotlin也來了,在Android之路上,留給我看Java的時間不多了。 靜態我們就來簡單介紹一下,使用靜態工廠方法建立物件相較於構造器建立的物件的優缺
Java物件學習之建立物件——使用靜態工廠方法代替構造器優點(二)
最近學習Android知識,發現Java好多的基礎知識運用的真的很一般,所以決定在重新梳理一下,現在Kotlin也來了,在Android之路上,留給我看Java的時間不多了。 靜態我們就來簡單介紹一下,使用靜態工廠方法建立物件相較於構造器建立的物件的優缺
Java物件學習之建立物件——使用靜態工廠方法代替構造器優點(一)
最近學習Android知識,發現Java好多的基礎知識運用的真的很一般,所以決定在重新梳理一下,現在Kotlin也來了,在Android之路上,留給我看Java的時間不多了。 靜態我們就來簡單介紹一下,使用靜態工
Android原始碼中引用@hide類出現引用異常的問題error: cannot find symbol
自己開發的APP在Android中使用一些系統隱藏的類 編譯的時候報錯,出現如下異常 error: cannot find symbol import android.net.EthernetM
Effective Java 第三版讀書筆記——條款1.考慮使用靜態工廠方法替代構造器
lean jdb 底層 public lasso 基本 win inter nds 獲取一個類的實例的傳統方法是使用公開的構造器,除此之外,一個類還可以提供公開的靜態工廠方法(static factory method)來返回它的實例。例如 Boolean 類中的 valu
Java中用靜態工廠方法代替構造器的優缺點
Effective Java學習筆記,靜態工廠方法的善用。 一般情況下,對於類而言,我們獲取一個類的例項時,最常用的方法是提供一個公有的構造器。 但是還有一種方法,類可以提供一個公有的靜態工廠方法,它只是個返回類的例項的靜態方法而已。但是靜態工廠方法卻又許多妙用之處。
Effective Java 第三版閱讀筆記——條款1.考慮使用靜態工廠方法替代構造器
獲取一個類的例項的傳統方法是使用公開的構造器,除此之外,一個類還可以提供公開的靜態工廠方法(static factory method)來返回它的例項。例如 Boolean 類中的 valueOf 方法,這個方法將基本型別 boolean 轉換為一個 Boolean 物件的引用: pub