1、App组件化
2、组件基本结构
(1)MVC
(2)MVP
(3)MVVM
(4)VIPER
3、设计模式
(1)单例模式
(2)Buildr模式
(3)Proxy模式
(4)……
4、参考文档
1、App组件化
之前写的一篇文章:App架构之组件化理解
组件间通过Router
通信,这个Router是业务无关的一个基础模块。可以通过Annotation实现。
组件化、模块化属于App级别的架构。
2、组件基本结构
下面的架构是属于组件或模块级别,而不是整个App的架构。
(1)MVC
Model:包括Bean数据结构、业务逻辑处理(如数据库操作、网络请求等)
View:就是展现出来的用户界面。
Controller:Model和View可以直接通信,没有完全起到隔离作用,不算一个纯粹的控制器。
存在的问题是:Model和View是耦合的。
(2)MVP
Model:包括Bean数据结构、业务逻辑处理
View:就是展现出来的用户界面。
Presenter:Model和View之间通信的桥梁,是一个控制器。
特点:Model和View解耦。
Demo参考:应用MVP模式写出可维护的优美Android应用
(3)MVVM
Model:包括Bean数据结构、业务逻辑处理
View:就是展现出来的用户界面。
ViewModel:就是与界面(view)对应的Model。因为,数据库结构往往是不能直接跟界面控件一一对应上的,所以,需要再定义一个数据对象专门对应view上的控件。而ViewModel的职责就是把model对象封装成可以显示和接受输入的界面数据对象。PS:不一定是Bean,里面可能也有业务逻辑处理,只不过这个是和View一一对应。和Presenter还是有差别。
View和ViewModel之间通过DataBinding进行双向绑定。
特点:和MVP相比,View和ViewModel通过DataBinding实现一一对应关系。
Demo参考:选择恐惧症的福音!教你认清MVC,MVP和MVVM
关于DataBinding:Android基础——框架模式MVVM之DataBinding的实践
关于ViewModel的理解参考:MVVM模式中ViewModel和View、Model有什么区别
(4)VIPER
View:展现出来的用户界面。
Presenter:View和Interactor之间的桥梁,相当于是一个控制器,不做具体业务逻辑。
Entity:Bean数据结构,不包括业务逻辑处理。
Interactor:业务逻辑处理。
Router:模块之间跳转,比如从当前A页面跳到B页面,就是由Router负责。(PS:如果有App级别的Router模块负责跳转,则组件内级别的Router跳转的话可以调用App级别的Router实现跳转)
VIPER模式,将MVP架构中原本由Model单独负责的Bean数据结构和业务逻辑处理分拆成2个类处理,Entity处理Bean数据结构,Interactor处理业务逻辑。此外在MVP基础上还增加了Router,负责模块跳转。
特点:和上面几个相比,减轻了Model的工作量,避免了胖Model
的问题(备注:胖Model和瘦Model)
参考:
在 Android 上使用 VIPER 架构
Architecting iOS Apps with VIPER
https://gist.github.com/marciogranzotto/1c96e87484a17bd914e159b2604e6469
延伸阅读:新版Uber App移动架构设计
uber/RIBs
https://github.com/uber/RIBs
https://juejin.im/post/5a9f88466fb9a028e46e308a
官网:
https://developer.android.com/topic/libraries/architecture/
TODO:clean architecture
个人观点:
MVP:适用于不太复杂的模块。
MVVM:需要引入DataBinding框架,用起来比较复杂,感觉和MVP相比也没啥优势。
VIPER:适用于逻辑比较复杂的模块,职责分明。
上面那些架构都是在MVC基础上的优化,并不是死的,并不一定要去套上面的模式,遵循一些模块化的基本原则即可。
3、设计模式
(1)单例模式
主要包括4种类型的写法:饿汉式
,双重检查锁
,静态内部类
,枚举
。且后面3种都属于懒汉式。
1.饿汉式
static final field
public class Singleton{
//类加载时就初始化
private static final Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
特点:类加载的时候就会创建单例。
缺点:不适用于实例创建依赖参数或者配置文件的场景;不适用于被使用的频率少的情况。
2.双重检查锁
public class Singleton{
private volatile static Singleton instance;
private Singleton (){}
public static Singleton getSingleton() {
if (instance == null) { //Single Checked
synchronized (Singleton.class) {
if (instance == null) { //Double Checked
instance = new Singleton();
}
}
}
return instance ;
}
}
//懒汉式,线程安全(不建议)
public class Singleton{
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
要点:
(1)instance = new Singleton()非原子操作
,可以拆分为如下4步:
- 栈内存开辟空间给instance引用
- 堆内存开辟空间
- 堆内存中初始化Singleton对象
- 栈中引用指向堆内存空间地址
(2)volatile
保证内存可见性,防止指令重排
。(Java 5
之前无效)
如果不使用volatile,new操作可能会出现指令重排,即执行顺序是1-2-4-3时,当第1个线程执行instance = new Singleton()操作,执行到1-2-4步时,这时第2个线程执行到Single Check这个位置的if (instance == null),发现非空就会返回单例,然而事实上这个单例对象还没有初始化完。
关于防止指令重排,实际上是会在volatile变量操作的前后插入内存屏障,使得位于屏障前的指令先于volatile指令执行,位于屏障后的指令后于volatile指令后执行。网上很多文章讲解要么不清楚要么有错误,这块还需要查书研究。
3.静态内部类
static nested class
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
特点:懒加载,只有在SingletonHolder类被引用时才会完成INSTANCE对象的实例化,利用ClassLoader机制保证线程安全。
4.枚举
Enum
public enum Singleton{
INSTANCE;
}
特点:枚举类是在第一次访问时才被实例化,默认线程安全;在反序列化
时可以自动防止重新创建新的对象。(枚举Java 5
之后才引入)
5.登记式单例
,使用 Map 容器来管理单例模式。
private static Map<String Singleton> objMap = new HashMap<String Singleton>();
public static void registerService(String key, Singleton instance) {
if (!objMap.containsKey(key) ) {
objMap.put(key, instance) ;
}
}
public static Singleton getService(String key) {
return objMap.get(key) ;
}
Android源码里各种系统Service就是就是使用的这种方式。比如:
private static void registerService(String serviceName, ServiceFetcher fetcher) {
if (!(fetcher instanceof StaticServiceFetcher)) {
fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
}
SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
}
@Override
public Object getSystemService(String name) {
// 根据name来获取服务
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
//注册ActivityManager
registerService(ACTIVITY_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
}
});
//注册LayoutInflater
registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
}
});
//获取LayoutInflater
LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
破坏单例模式的场景:
- 序列化
- 反射
- 克隆(实现 Cloneable 接口)
参考:
那些年,我们一起写过的“单例模式”
如何正确地写出单例模式
(2)Buildr模式
定义
:将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。
使用场景
:
- 需要生成的产品对象有
复杂的内部结构
,这些产品对象具备共性
; 隔离
复杂对象的创建和使用,并使得相同的创建过程
可以创建不同的产品。
AlertDialog就是Builder模式,源码如下:
//Product
public class AlertDialog extends Dialog implements DialogInterface {
private AlertController mAlert;
protected AlertDialog(Context context) {
this(context, resolveDialogTheme(context, 0), true);
}
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
public void setMessage(CharSequence message) {
mAlert.setMessage(message);
}
public void setView(View view) {
mAlert.setView(view);
}
//Builder
public static class Builder {
private final AlertController.AlertParams P;
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
public Builder(Context context, int theme) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, theme)));
mTheme = theme;
}
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
public Builder setView(View view) {
P.mView = view;
P.mViewLayoutResId = 0;
P.mViewSpacingSpecified = false;
return this;
}
public AlertDialog create() {
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
}
}
用户调用代码,即Director:
private void showDialog(Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(R.drawable.icon);
builder.setTitle("Title");
builder.setMessage("Message");
builder.setPositiveButton("Button1",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
setTitle("点击了对话框上的Button1");
}
});
builder.setNeutralButton("Button2",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
setTitle("点击了对话框上的Button2");
}
});
builder.setNegativeButton("Button3",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
setTitle("点击了对话框上的Button3");
}
});
builder.create().show(); // 构建AlertDialog, 并且显示
}
(3)Proxy模式
定义
:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
使用场景
:客户不想或者不能够直接引用一个目标对象时,代理对象可以在客户和目标对象之间起到中介的作用。
Android源码中的ActivityManagerService涉及到2个知识点。即Proxy模式
和Binder机制
。
下面的代码体现了Proxy设计模式:
//RealObject(ActivityManagerService继承了ActivityManagerNative)
public abstract class ActivityManagerNative extends Binder implements IActivityManager {
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case START_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
String callingPackage = data.readString();
Intent intent = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
IBinder resultTo = data.readStrongBinder();
String resultWho = data.readString();
int requestCode = data.readInt();
int startFlags = data.readInt();
ProfilerInfo profilerInfo = data.readInt() != 0 ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
Bundle options = data.readInt() != 0 ? Bundle.CREATOR.createFromParcel(data) : null;
int result = startActivity(app, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
reply.writeNoException();
reply.writeInt(result);
return true;
}
...
}
}
//ProxyObject
class ActivityManagerProxy implements IActivityManager {
public ActivityManagerProxy(IBinder remote) {
mRemote = remote;
}
public IBinder asBinder() {
return mRemote;
}
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
//将数据装进data
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
//创建空的reply
Parcel reply = Parcel.obtain();
//请求服务端对象,执行任务
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
//任务执行完后,得到reply
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
}
(4)……
4、参考文档
(1)https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
(2)https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter
(3)https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel
(4)iOS应用架构谈
(5)iOS 架构模式–解密 MVC,MVP,MVVM以及VIPER架构
(6)Android源码设计模式分析项目
(7)https://blog.csdn.net/column/details/14783.html