抽象工厂应用是很广的,在Android源码中,这个IPolicy就是一个简单的抽象工厂模式。下面分析一下IPolicy及其实现,以及创建的相关对象(源码基于5.0.0)。
抽象工厂
意图
提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
UML类图
通过继承抽象工厂,可以产生不同的产品系列
代码示例
abstract class AbsFactory{
public abstract AbsProductA createProduct1();
public abstract AbsProdcutB createProduct2();
}
abstract class AbsProductA{
}
abstract class AbsProductB{
}
class ProductA1 extends AbsProductA{
}
class ProductB1 extends AbsProductB{
public void interactWithProductA(AbsProductA product){ //与ProductA关联
}
}
class ConcreteFactory1 extends AbsFactory{
private static ConcreteFactory instance = new ConcreteFactory();
public ConcreteFactory getInstance(){
return instance;
}
public AbsProductA createProductA(){
return new ProductA1();
}
public AbsProdcutB createProductB(){
return new ProductB1();
}
}
public static void main(String[] args){
ConcreteFactory instance = ConcreteFactory.
AbsProductA product1 = instance.createProductA();
AbsProductB product2 = instance.createProductB();
product2.interactWithProductA(product1);
}
抽象工厂就是创建一系列相互关联的对象,这样每一个抽象工厂的具体实现创建的对象都是相互关联的,而且可以是不同的产品系列,相当于从上层就设计好了一套产品规范。这里只是简单介绍了一下抽象工厂。如果想很好的理解可以参考设计模式:可复用面向对象软件的基础关于抽象工厂的介绍。下面介绍IPolicy。
IPolicy
IPolicy在com.android.internal.policy包下面。它是关于Android窗口,窗口管理,布局加载,以及事件回退Handler这一系列窗口相关产品的抽象工厂。先看IPolicy的UML类图。
UML图
IPolicy是产生窗口屏幕相关对象的抽象接口,在Android手机源码中,com.android.internal.policy.impl.Policy是它的唯一一个实现,按照源码中的注释所说的,是Policy是IPolicy的一个简单实现,用来生成对象集合。Policy创建一系列的Phone的窗口相关对象:PhoneWindow,PhoneLayoutInflater,PhoneWindowManager,PhoneFallbackEventHandler。从UML图就可以看出,IPolicy算是一个典型的抽象工厂,只不过在源码中只有一个具体的工厂实现。
另外Policy的实现还有一点特殊的地方,它使用static域将他需要创建的对象都预先load出来,也就是说当虚拟机加载Policy类的时候,就会加载它创建的对象的class。
相关对象介绍
下面分别介绍IPolicy创建的每个对象
PolicyManager
PolicyManager相当于是这个抽象工厂的客户端,它只有静态方法,他它的静态方法跟IPolicy的接口是相对应的。它内部包含了一个Policy对象,相当于是Policy的一个代理,对应的创建操作都会交给Policy去创建,比如说makeNewWindow方法的实现:
// The static methods to spawn new policy-specific objects
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
Window与PhoneWindow
Window是Android中的窗口,每个Activity都会对应着一个Window,在Activity的attach方法中,就有Window的创建代码:
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
mFragments.attachActivity(this, mContainer, null);
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
...
attach方法是将Context,application等赋值给Activity,在Activiy启动的过程会调用。我们弹出的对话框(Dialog),里面也是有一个Window的。另外与Activity对应的还有启动窗口(Starting Window)。一个Window还可以有子Window。另外Android中还有一些其他的窗口还有输入法窗口,状态栏窗口,壁纸窗口。
窗口有一个专门的窗口管理服务WindowManagerService,在WindowManagerService中与每个Activity对应的为AppWindowToken,而AppWindowToken描述的是一组窗口(一组WindowState),对应于Activity中Context的各种窗口。
而手机中, Window的具体实现是PhoneWindow。PhoneWindow是对应着Android手机的Window实现。PhoneWindow里面包含了DecorView, DecorView包含了标题栏以及具体View(由setContentView设置)。它们之间的关系如下:
而真正直接关联Window与View的是WindowManager,由Window.setWindowManager设置。每个Window都会对应一个WindowManager。通过WindowManager的addView,updateViewLayout,removeView来添加,更新,移除Window中的View。
通过context.getSystemService(Context.WINDOW_SERVICE)可以获得WindowManager,这个就是Activity的mWindow的WindowManager,而WindowManager的具体实现是WindowManagerImpl,而WindowManagerImpl又会将Window的相关操作(addView, removeView)交给WindowManagerGlobal来实现。WindowManagerGlobal是一个单例模式,里面包含了一个ViewRootImpl列表(ArrayList),一个View列表, 一个WindowManager.LayoutParams列表,三个链表相互对应,表示一个View对应的LayoutParams和ViewRoot。WindowManagerGlobal获取了WindowManagerService的Binder接口IWindowManager。ViewRootImpl通过WindowManagerGlobal的IWindowManager获取WindowSession(Binder的Proxy),将ViewRootImpl的W(Binder对象)传给WindowManagerService,来与WindowManagerService相互通信。他们之间的UML图如下:
WindowManagerPolicy,PhoneWindowManager
这个WindowManagerPolicy不同于Window中介绍的WindownManager,Window中介绍的WindowManager是属于Window与View交互的管理,而WindowManagerPolicy则是更多地倾向于对Window屏幕的管理,比如说启动窗口就是由它创建的。也包括一个具体的屏幕管理,比如说获取屏幕显示的大小,屏幕旋转,屏幕设置等等。PhoneWindowManager是WindowManagerPolicy在手机规格下的实现。WindowManagerPolicy还有一个内部静态类WindowManagerPolicy.WindowState,它是由WindowManagerService管理的,从一个窗口开始添加就存在,到窗口移除就删除,是一个窗口的状态接口,可以获得当前窗口所属的进程,包名,当前的Frame
LayoutInflater,PhoneLayoutInflater
LayoutInflater应该都比较熟悉,它是Android中用于XML布局加载的类,它是一个抽象类,PhoneLayoutInflater是它在Android手机上面的实现。PhoneLayoutInflater中主要是实现了onCreateView方法和cloneInContext方法。
FallbackEventHandler,PhoneFallbackEventHandler
这个是回退事件Handler,主要是为了处理回退事件(Fallback)。
IPolicy抽象工厂的设计分析
如果只看IPolicy,PolicyManager,Policy的UML,你会发现其实这三个部分也像是一个策略模式的UML图。这部分里面本身也可以说是一种策略,一种创建的策略。但把IPolicy作为抽象工厂理解会更为合适,它负责生成一系列相关产品,却不用管产品的具体实现。
首先说说这四个产品之间的关系,Window是表示窗口,抽象的窗口管理,而WindowManagerPolicy是关于窗口屏幕的管理策略,LayoutInflater是XML解析器,将XML解析为Window中具体元素View,最后FallbackEventHandler是回退事件Handler,事件会作用在窗口上面。这四个产品在不同的产品簇的具体表现会是不一样的,但是他们又有相互之间的关联。用一个统一的创建接口,在使用这些接口的时候会更加方便。
就拿Phone的这四种产品实现来说,Phone的Window,以及WindowManagerPolicy自然是不同的,另外LayoutInflater也会有所不同,比如XML的View可能限制不一样,在PhoneLayoutInflater中会从包名前缀为”android.widget.”,”android.webkit.”,”android.app.”这三个来创建View。另外如果产品簇是TV的话,FallbackEventHandler处理可能是直接回退到上一个台,而Phone的话会是返回上一个操作。
用四个工厂方法实现
其实四种不同的产品(Window,WindowManagerPolicy,LayoutInflater,是XML解析器,将XML解析为Window中具体元素View,最后FallbackEventHandler),如果用四个工厂方法也肯定是可以的,但是会缺乏将本来应该有相互关联的产品拆分开了,抽象工厂一定程度上提高了它们之间的耦合性。
扩展优势分析
假如除了Phone外,又突然有了一种新的产品簇(比如说TV,智能手表,我暂时并没有调查这两种的实现方式),那么只需要创建一个对应Policy,以及对应的产品系列,然后将PolicyManager的IPolicy指向新产品簇的Policy就好了。