Android源码学习之工厂方法模式应用及优势介绍

工厂方法模式定义
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

常用的工厂方法模式结构

如上图所示(截取自《Head First Design Patterns》一书),主要包括四个部分:
抽象产品类Product负责定义产品的共性,实现对事物抽象的定义;Creator是抽象创建类,也就是抽象工厂,具体如何创建产品类是由具体的实现工厂ConcreteCreator完成的。其中在《Head First Design Patterns》对工厂方法模式做了细节的说明,原文如下:
As in the official definition, you'll often hear developers say that the Factory Method lets subclasses decide which class to instantiate. They say “decides” not because the pattern allows subclasses themselves to decide at runtime, but because the creator class is written without knowledge of the actual products that will be created, which is decided purely by the choice of the subclass that is used.

工厂方法模式有什么优势呢
良好的封装性,代码结构清楚。一个对象创建具有条件约束的,如果一个调用者需要一个具体的产品对象,只要知道这个产品的类名就可以了,不用知道创建对象的过程,降低模块间的耦合。

可扩展性好。在增加产品类的情况下,只要适当的修改具体的工厂类或扩展一个工厂类,就可以完成。
屏蔽产品类。产品类的实现如何变化,调用者都不需要关心,它只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不用改变。因为产品类的实例化工作是由工厂类负责的,一个产品对象具体由哪一个产品生成是由工厂类决定的。此外工厂方法模式是典型的松耦合结构。高层模块只需要知道产品的抽象类,其他的实现类都不用关系,符合迪米特法则、依赖倒置原则、里氏替换原则等。

在Android源码中,ListActivity继承自Activity,将Activity作为工厂方法,生成具有ListView特点的Activity,对ListActivity的说明如下:
An activity that displays a list of items by binding to a data source such as an array or Cursor, and exposes event handlers when the user selects an item.
ListActivity hosts a ListView object that can be bound to different data sources, typically either an array or a Cursor holding query results. Binding, screen layout, and row layout are discussed in the following sections.

Screen Layout
ListActivity has a default layout that consists of a single, full-screen list in the center of the screen. However, if you desire, you can customize the screen layout by setting your own view layout with setContentView() in onCreate(). To do this, your own view MUST contain a ListView object with the id "@android:id/list" (or listif it's in code)

在Activity类中有这么一个函数


代码如下:

/**
* This method is called after {@link #onStart} when the activity is
* being re-initialized from a previously saved state, given here in
* <var>savedInstanceState</var>. Most implementations will simply use {@link #onCreate}
* to restore their state, but it is sometimes convenient to do it here
* after all of the initialization has been done or to allow subclasses to
* decide whether to use your default implementation. The default
* implementation of this method performs a restore of any view state that
* had previously been frozen by {@link #onSaveInstanceState}.
*
* <p>This method is called between {@link #onStart} and
* {@link #onPostCreate}.
*
* @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
*
* @see #onCreate
* @see #onPostCreate
* @see #onResume
* @see #onSaveInstanceState
*/
protected void onRestoreInstanceState(Bundle savedInstanceState) {
if (mWindow != null) {
Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
if (windowState != null) {
mWindow.restoreHierarchyState(windowState);
}
}
}

在注释中“but it is sometimes convenient to do it here after all of the initialization has been done or to allow subclasses to decide whether to use your default implementation.”,英语不太好,但大致的意思是Activity子类可以重载这个函数来决定是否使用默认的实现。

在看子类ListActivity


代码如下:

public class ListActivity extends Activity {
/**
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
protected ListAdapter mAdapter;
/**
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
protected ListView mList;
private Handler mHandler = new Handler();
private boolean mFinishedStart = false;
private Runnable mRequestFocus = new Runnable() {
public void run() {
mList.focusableViewAvailable(mList);
}
};
/**
* This method will be called when an item in the list is selected.
* Subclasses should override. Subclasses can call
* getListView().getItemAtPosition(position) if they need to access the
* data associated with the selected item.
*
* @param l The ListView where the click happened
* @param v The view that was clicked within the ListView
* @param position The position of the view in the list
* @param id The row id of the item that was clicked
*/
protected void onListItemClick(ListView l, View v, int position, long id) {
}
/**
* Ensures the list view has been created before Activity restores all
* of the view states.
*
*@see Activity#onRestoreInstanceState(Bundle)
*/
@Override
protected void onRestoreInstanceState(Bundle state) {
ensureList();
super.onRestoreInstanceState(state);
}
/**
* @see Activity#onDestroy()
*/
@Override
protected void onDestroy() {
mHandler.removeCallbacks(mRequestFocus);
super.onDestroy();
}
/**
* Updates the screen state (current list and other views) when the
* content changes.
*
* @see Activity#onContentChanged()
*/
@Override
public void onContentChanged() {
super.onContentChanged();
View emptyView = findViewById(com.android.internal.R.id.empty);
mList = (ListView)findViewById(com.android.internal.R.id.list);
if (mList == null) {
throw new RuntimeException(
"Your content must have a ListView whose id attribute is " +
"'android.R.id.list'");
}
if (emptyView != null) {
mList.setEmptyView(emptyView);
}
mList.setOnItemClickListener(mOnClickListener);
if (mFinishedStart) {
setListAdapter(mAdapter);
}
mHandler.post(mRequestFocus);
mFinishedStart = true;
}
/**
* Provide the cursor for the list view.
*/
public void setListAdapter(ListAdapter adapter) {
synchronized (this) {
ensureList();
mAdapter = adapter;
mList.setAdapter(adapter);
}
}
/**
* Set the currently selected list item to the specified
* position with the adapter's data
*
* @param position
*/
public void setSelection(int position) {
mList.setSelection(position);
}
/**
* Get the position of the currently selected list item.
*/
public int getSelectedItemPosition() {
return mList.getSelectedItemPosition();
}
/**
* Get the cursor row ID of the currently selected list item.
*/
public long getSelectedItemId() {
return mList.getSelectedItemId();
}
/**
* Get the activity's list view widget.
*/
public ListView getListView() {
ensureList();
return mList;
}
/**
* Get the ListAdapter associated with this activity's ListView.
*/
public ListAdapter getListAdapter() {
return mAdapter;
}
private void ensureList() {
if (mList != null) {
return;
}
setContentView(com.android.internal.R.layout.list_content_simple);
}
private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
{
onListItemClick((ListView)parent, v, position, id);
}
};
}

其中复写了函数onRestoreInstanceState(Bundle state),并在View中设置了默认的setContentView(com.android.internal.R.layout.list_content_simple);


代码如下:

/**
* Ensures the list view has been created before Activity restores all
* of the view states.
*
*@see Activity#onRestoreInstanceState(Bundle)
*/
@Override
protected void onRestoreInstanceState(Bundle state) {
ensureList();
super.onRestoreInstanceState(state);
}
。。。
private void ensureList() {
if (mList != null) {
return;
}
setContentView(com.android.internal.R.layout.list_content_simple);
}

Activity中的setContentView()函数


代码如下:

/**
* Set the activity content from a layout resource. The resource will be
* inflated, adding all top-level views to the activity.
*
* @param layoutResID Resource ID to be inflated.
*
* @see #setContentView(android.view.View)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
*/
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
initActionBar();
}
/**
* Set the activity content to an explicit view. This view is placed
* directly into the activity's view hierarchy. It can itself be a complex
* view hierarchy. When calling this method, the layout parameters of the
* specified view are ignored. Both the width and the height of the view are
* set by default to {@link ViewGroup.LayoutParams#MATCH_PARENT}. To use
* your own layout parameters, invoke
* {@link #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}
* instead.
*
* @param view The desired content to display.
*
* @see #setContentView(int)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
*/
public void setContentView(View view) {
getWindow().setContentView(view);
initActionBar();
}
/**
* Set the activity content to an explicit view. This view is placed
* directly into the activity's view hierarchy. It can itself be a complex
* view hierarchy.
*
* @param view The desired content to display.
* @param params Layout parameters for the view.
*
* @see #setContentView(android.view.View)
* @see #setContentView(int)
*/
public void setContentView(View view, ViewGroup.LayoutParams params) {
getWindow().setContentView(view, params);
initActionBar();
}

总结:Activity作为“工厂方法”,具体View中显示什么由默认设置或者由子类来实现;ListActivity作为具体实现,它决定在View中显示的是ListView;这里的View是Activity中的默认显示,即为“Product”,而ListView是“ConcreteProduct”,由ListActivity来决定显示。

除了ListActivity以外,还有ExpandableListActivity也是以Activity为工厂类,创建自己的显示效果。
本人能力和时间有限(缺少“模式使用”内容,以后会添加),写的很粗糙,恭候大家的批评指正,谢谢~~~

(0)

相关推荐

  • android开发中使用java观察者模式

    复制代码 代码如下: //观察者,需要用到观察者模式的类需实现此接口public interface Observer { void update(Object... objs);} //被观察者(一个抽象类,方便扩展)public abstract class Observable { public final ArrayList<Class<?>> obserList = new ArrayList<Class<?>>(); /** Attach Obs

  • Android回调与观察者模式的实现原理

    回调与观察者模式的实现原理:废话不多说,直接上Demo回调的原理: 观察者模式: A类中定义一个被观察者画家 package com.example.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.view.View; import java.util.ArrayList; /** * user: uidq0530

  • Android源码学习之单例模式应用及优点介绍

    单例模式定义: Ensure a class has only one instance, and provide a global point of access to it. 动态确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 如上图所示(截取自<Head First Design Patterns>一书). 通过使用private的构造函数确保了在一个应用中产生一个实例,并且是自行实例化(在Singleton中自己使用new Singleton()). 具体单例模式有

  • Android源码学习之观察者模式应用及优点介绍

    观察者模式定义: Define a one-to-many dependency between objects so that when one object changes state, all its dependents aer notified and updated automatically. 定义对象间一种一对多的依赖关系,使得当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新.  如上图所示(截取自<Head First Design Patterns>一书),

  • android设计模式之单例模式详解

    这是我们最常见的一类模式,对这一类模式有一个通用的特点就是: 封装创建的方式和过程. 这里所谓封装就是隐藏的意思,对对象的创建方法和过程不可见,或者是虚拟的过程. 隐藏创建方式,就是如单例,工厂方法,隐藏创建过程则是指builder,原型,至于抽象工厂,我认为他包含了以上两种. 我们想想一个对象的创建有哪些步骤? 1.创建什么东西?--接口定义 2.谁创建?        --决策类or帮助类 3.如何创建?     --how,创建过程 4.什么时候创建?    --创建时机的触发 由此可知,

  • Android开发实现简单的观察者与被观察者示例

    本文实例讲述了Android开发实现简单的观察者与被观察者.分享给大家供大家参考,具体如下: 概述: 观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己. 观察者模式结构图 Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个

  • Android观察者模式实例分析

    本文实例讲述了Android观察者模式.分享给大家供大家参考.具体分析如下: 一.环境: 主机:WIN8 开发环境:Eclipse 二.说明: 1.打开sd卡中的xml文件,如果不存在,这新建一个,并写入默认配置 2.读取xml文件 3.Config_Info.java为配置信息数据结构 4.IF_Config.java为配置类的存取接口,其他类可以通过此接口直接获取配置信息 5.IF_Subject_Config.java为观察者模式目标类接口 6.IF_Observer_Config.jav

  • android基础教程之夜间模式实现示例

    复制代码 代码如下: package org.david.dayandnightdemo.cor; import android.os.Bundle;import android.app.Activity;import android.content.Context;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.graphics.Col

  • Android 听筒模式的具体实现实例

    一.利用距离感应器监听听筒靠近耳朵事件准确的说距离感应器并不能监听到你是否把手机靠近耳朵,也许是你用手挡在了距离感应器前面,但这不是我们关心的,我们关心的是当你的耳朵靠近听筒时,我们要捕获到这个事件 step 1,新建实现SensorEventListener接口的类并实现onSensorChanged(SensorEvent event)方法 复制代码 代码如下: public class MainActivity extends Activity implements SensorEvent

  • Android源码学习之工厂方法模式应用及优势介绍

    工厂方法模式定义: Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses. 定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类. 常用的工厂方法模式结构: 如上图所示(截取自<Head Firs

  • Android源码学习之组合模式定义及应用

    组合模式定义: Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly. 将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性. 如上图所示(截取自<Head First De

  • java设计模式学习之工厂方法模式

    工厂方法模式(Factory Method):定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类. 工厂方法模式结构图: 项目需求,创建一个雷锋工厂,大学生可以去帮助别人,志愿者也可以帮助别人做事情. 1:创建一个雷锋类,具有帮助别人扫地,洗衣,买米的功能. package FactoryMethodModel; public class LeiFeng { public void Sweep(){ System.out.println("扫地"

  • Android编程设计模式之工厂方法模式实例详解

    本文实例讲述了Android编程设计模式之工厂方法模式.分享给大家供大家参考,具体如下: 一.介绍 工厂方法模式(Factory Pattern),是创建型设计模式之一.工厂方法模式是一种结构简单的模式,其在我们平时开发中应用很广泛,也许你并不知道,但是你已经使用了无数次该模式了,如Android中的Activity里的各个生命周期方法,以onCreate方法为例,它就可以看作是一个工厂方法,我们在其中可以构造我们的View并通过setContentView返回给framework处理等,相关内

  • Android Studio如何查看源码并调试的方法步骤

    背景 最近遇到一个Dialog问题,在6.0的手机上才可以重现,但是我们的工程已经是targetsdk=28了,点击Dialog的引用,只能看见28的class文件,现在我也越来越懒了,以前针对这种问题,我都会写个demo,去重现问题,但是现在希望能直接在当前工程快速定位出原因,能够基于源码debug肯定更好了,为了实现这个懒的目标,我找了很多办法,下面就一一介绍下 方法一 切换compilesdk studio默认使用的是gradle里配置的compilesdkversion,只要你把comp

  • Android源码导入AndroidStudio或IntelliJ IDEA的方法

    目录 一.前言 二.idegen使用方法 1. 全编AOSP 2. 编译生成idegen.jar 3. 生成IDE配置文件 4. 将工程导入到IDE 一.前言 经常和Android系统源代码(AOSP)打交道的人,如果要去修改系统源码,显然用SourceInsight.Notepad++.vim这些工具有些麻烦,并且想快速补全代码也做不到.我们可以用idegen来生成针对AndroidStudio或IntelliJ IDEA的Android系统源代码工程配置文件,它位于Android系统源代码工

  • C#实现工厂方法模式

    场景:简单工厂时候,我设计了一个场景,有三种剑去打怪,这时候,需求变化了,我三种剑变成了,匕首.剑以及木棒,想要用工厂方法来实现,怎么弄? 1.上文讲过简单工厂模式,它的最大优点在于工厂类内有创建类型的判断逻辑,客户端只需要通过动态的选择想要创建的类型,就可以交给工厂类来创建,去除了客户与具体产品之间的依赖. 缺点在于,当新建一个类型的时候,需要修正工厂类中的判断逻辑,添加一个case,此时就违背了开放-封闭原则. 2.工厂方法模式的引入:定义一个用于创建对象的接口,让子类觉得实例化哪一个类,工

  • Android源码探究之BaseDexClassLoader的使用

    目录 前言 一.dexPath(String) 二.optimizedDirectory 三.librarySearchPath 四.parent 五.总结 前言 一共有4个参数,分来来讲. 1:dexFile(String类型)2:optimizedDirectory(File类型)3:librarySearchPath(String类型)4:parent(ClassLoader类型) 一.dexPath(String) 官方的注释: * @param dexPath the list of

随机推荐