一、单例模式
单例模式是一种对象创建模式,它用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销。由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。
1)、饿汉:这种方式可以避免多线程的同步问题,但是无法对实例做延时加载。
public class Singleton {
private static Singleton singleton = new Singleton();
public static Singleton getInstance(){
return singleton;
}
}
2)、懒汉:这种方式采用了懒加载模式,在第一次使用时才去初始化对象,节省了资源,但是第一次使用时需要初始化,同时多线程的时候不能保证实例唯一的。
public class Singleton {
private static Singleton singleton ;
public static Singleton getInstance(){
if(singleton == null)
singleton = new Singleton();
return singleton;
}
}
3)、懒汉线程安全:这种方式可以在多线程环境下安全工作,但是每次调用getInstance()方法都要进行同步,造成不必要的开开销,而且大部分时候我们是用不到同步的,所以不建议采用这种方式。
//写法一
public class Singleton {
private static Singleton singleton ;
public static Singleton getInstance(){
synchronized (Singleton.class) {
if(singleton == null)
singleton = new Singleton();
}
return singleton;
}
}
//写法二
public class Singleton {
private static Singleton singleton ;
public synchronized static Singleton getInstance(){
if(singleton == null)
singleton = new Singleton();
return singleton;
}
}
4)、双重检查DCL:这种写法在getInstance()方法中进行了两次空判断,第一次是为了避免不必要的同步,第二次是在singleton为空的情况下才创建实例。但是在new DclSingleton()的时候不是原子安全,因为JVM在即使编译器中存在指令重排序的优化作用,可能是先赋值在实例化顺序得不到保证,因此需要对单例对象进行volatile修饰。
public class Singleton {
private static Singleton singleton; //为了保证原子安全,最好加上volatile修饰
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null)
singleton = new Singleton();
}
}
return singleton;
}
}
5)、静态内部类:加载一个类时,其内部的类不会同时被加载,当且仅当某个静态成员(静态成员变量,构造方法,静态方法)被调用时才去加载。第一次加载Singleton时并不会初始化singleton,只有第一次调用那个getInstance()方法时才会加载SingletonHolder,并且初始化singleton,这样不仅能够保证线程的安全性也能保证Singleton类的唯一性。
public class Singleton {
public static Singleton getInstance() {
return SingletonHolder.singleton;
}
private static class SingletonHolder {
private static final Singleton singleton = new Singleton();
}
}
6)、枚举:你可以通过Singleton.INSTANCE来访问,比较方便,线程安全,防止反序列化创建新的对象,但是失去了一些类的特性,没有延迟加载,而且可读性较差,所以很少有人使用。
public enum Singleton{
INSTANCE;
public void doSomething(){ }
}
总结:
- 饿汉:无法对instance实例进行延迟加载
- 懒汉:对instance实例进行延迟加载,但是多线程并发情况下无法保证实例的唯一性
- 懒汉线程安全:对instance实例进行延迟加载,多线程保证了实例唯一性,但是使用synchronized导致性能缺陷
- DCL:对instance实例进行延迟加载,多线程保证了实例唯一性,也弥补了synchronized性能缺陷,但是JVM存在编译器的指令重排序,可以对实例对象进行volatile修饰
- 静态内部类:对instance实例进行延迟加载,多线程保证了实例唯一性,也没有性能缺陷,最佳方法
- 枚举:对instance实例进行延迟加载,线程安全,并性能缺陷,但是可读性很差,不能兼容前面几个版本
应用:
- application
- 单例模式引起的内存泄漏
- eventbus的坑
二、创建模式
Builder模式是一步一步创建一个复杂对象的创建型模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。当构造一个对象需要很多参数或者参数的个数或者类型不固定的时候,应用Builder模式可以将对象的构建与表示进行分离提高代码可读性。
1)、常用方式创建多参数的复杂对象
- 重叠构造器模式 :这种方式创建一个复杂对象,当有许多参数的时候,创建使用代码会很难写,并且较难以阅读,如下:
public class Person{
public Person(int id, String name) {
this(id, name, 0);
}
public Person(int id, String name, int age) {
this(id, name, age, "");
}
public Person(int id, String name, int age, String sex) {
this(id, name, age, sex, "");
}
public Person(int id, String name, int age, String sex, String phone) {
this(id, name, age, sex, phone, "");
}
public Person(int id, String name, int age, String sex, String phone, String address) {
this(id, name, age, sex, phone, address, "");
}
public Person(int id, String name, int age, String sex, String phone, String address, String desc) {
this.id = id;
this.name = name;
this.age = age;
this.sex = sex;
this.phone = phone;
this.address = address;
this.desc = desc;
}
}
- JavaBeans模式 :这种模式弥补了重叠构造器模式的不足。创建实例很容易,代码可读性高,但是构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的状态。类无法仅仅通过检验构造器参数的有效性来保证一致性。
public class Person{
public Person(){ super() }
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setPhone(String phone) {
this.phone = phone;
}
public void setAddress(String address) {
this.address = address;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
2)、UML类图:
- Product 产品类:被创建的复杂对象,参数很多或者参数不固定
- Builder 构建者抽象类:可以是接口或抽象类用来规范产品的创建,具体创建由子类完成,在简单的应用时可以省略
- ConcreteBuilder 构建者:是Builder的子类,具体实现创建的过程和参数的组装,在一些场景下可以直接使用不用将父类抽象成接口出来
- Director :统一组装的接口,可以对不同的具体构建者进行封装,有点类似工厂模式原理
3)、简单的Builder模式通用代码:
//产品类 (复杂对象)
public class Person {
private String name;
private int age;
private double height;
private double weight;
public Person(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
//建造者类 这里没有对Builder进行抽象出来
//定义一个静态内部类Builder 内部的成员变量和外部类一样
//Builder类通过一系列的方法用于成员变量的赋值 并返回当前对象本身(this)
public static class Builder{
private Person person;
public Builder(){
super();
person=new Person();
}
public Builder setName(String name) {
person.setName(name);
return this;
}
public Builder setAge(int age) {
person.setAge(age);
return this;
}
public Builder setHeight(double height) {
person.setHeight(height);
return this;
}
public Builder setWeight(double weight) {
person.setWeight(weight);
return this;
}
//Builder类提供一个build方法或者create方法用于创建对应的外部类
public Person build(){
return person; //build()返回Person对象
}
}
}
4)、复杂的Builder模式:
//产品类
public class Product {
public static final String ANDROID = "android";
public static final String IOS = "ios";
private String appName;
private String appFuction;
private String appSystem;
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getAppFuction() {
return appFuction;
}
public void setAppFuction(String appFuction) {
this.appFuction = appFuction;
}
public String getAppSystem() {
return appSystem;
}
public void setAppSystem(String appSystem) {
this.appSystem = appSystem;
}
}
//抽象建造者类
public abstract class Build {
public abstract Build setAppName(String appName);
public abstract Build setAppFuction(String appFuction);
public abstract Build setAppSystem(String appSystem);
public abstract Product build();
}
//具体建造者类
public class WorkBuilder extends Build {
private Product product; //产品类
private InnerProduct innerProduct = new InnerProduct(); //产品参数缓存类
@Override
public Build setAppName(String appName) {
innerProduct.appName=appName;
return this;
}
@Override
public Build setAppFuction(String appFuction) {
innerProduct.appFuction=appFuction;
return this;
}
@Override
public Build setAppSystem(String appSystem) {
innerProduct.appSystem=appSystem;
return this;
}
@Override
public Product build() { //可以对组装的顺序进行统一管理
product = new Product();
product.setAppName(innerProduct.getAppName());
product.setAppFuction(innerProduct.getAppFuction());
product.setAppSystem(innerProduct.getAppSystem());
return product;
}
private class InnerProduct { //产品参数缓存类
public String appName;
public String appFuction;
public String appSystem;
}
}
//指挥者类 可以进一步对不同的Builder进行封装
public class Director {
public static Product create(String system) {
return new WorkBuilder().setAppSystem(system)
.setAppName("探").setAppFuction("划一划找妹子").build();
}
}
5)、Builder模式的特点:
- 优点:松散耦合,可以用同一个构建算法构建出表现上完全不同的产品,实现产品构建和产品表现上的分离
- 缺点:会产生多余的Builder对象,对象的构建过错被暴露
6)、AlertDialog源码解析:
在Android源码中,我们最常用到的Builder模式就是AlertDialog.Builder, 使用该Builder来构建复杂的AlertDialog对象:
public class AlertDialog extends AppCompatDialog implements DialogInterface {
//Controller 接受Builder成员变量P中的各个参数
private AlertController mAlert;
protected AlertDialog(Context context, int theme) {
this(context, theme, true);
}
//构造方法中 实例化了AlertController
AlertDialog(Context context, int theme, boolean createContextWrapper) {
super(context, resolveDialogTheme(context, theme), createContextWrapper);
mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController(getContext(), this, getWindow());
}
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
public void setCustomTitle(View customTitleView) {
mAlert.setCustomTitle(customTitleView);
}
public void setMessage(CharSequence message) {
mAlert.setMessage(message);
}
//在onCreate方法实际上调用的mAlert的installContent进行视图设置
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
...省略代码...
//Builder为静态内部类
public static class Builder {
//存储AlertDialog的各个参数 例如title, message, icon等.
private final AlertController.AlertParams P;
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
//对AlertController.AlertParams进行实例化
public Builder(Context context, int theme) {
P = new AlertController.AlertParams(new ContextThemeWrapper(context, resolveDialogTheme(context, theme)));
mTheme = theme;
}
//通过builder设置的参数,实际上是设置给AlertController.AlertParams
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
public Builder setIcon(int iconId) {
P.mIconId = iconId;
return this;
}
public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
P.mPositiveButtonText = text;
P.mPositiveButtonListener = listener;
return this;
}
public Builder setView(View view) {
P.mView = view;
P.mViewSpacingSpecified = false;
return this;
}
//构建AlertDialog 可以进行构建的顺序管理
public AlertDialog create() {
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
//P里面的所有信息应用到AlertDialog的AlertController
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
}
}
通过Builder来设置AlertDialog中的title, message, button等参数, 这些参数都存储在类型为AlertController.AlertParams的成员变量P中,AlertController.AlertParams中包含了与之对应的成员变量。在调用Builder类的create函数时才创建AlertDialog, 并且将Builder成员变量P中保存的参数应用到AlertDialog的mAlert对象中,即P.apply(dialog.mAlert)代码段
class AlertController {
private final Context mContext;
private final AppCompatDialog mDialog;
private final Window mWindow;
private Handler mHandler;
...省略代码...
//调用了Window对象的setContentView进行视图资源设置 实际上Activity最终也是调用Window对象的setContentView
public void installContent() {
final int contentView = selectContentView();
mDialog.setContentView(contentView);
setupView();// setupView
}
private int selectContentView() {
if (mButtonPanelSideLayout == 0) {
return mAlertDialogLayout;
}
if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {
return mButtonPanelSideLayout;
}
return mAlertDialogLayout;//AlertDialog的布局id
}
//通过上面的配置的参数进行视图的构建
private void setupView() {
// 获取并初始化内容区域
final View parentPanel = mWindow.findViewById(R.id.parentPanel);
final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);
final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);
final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);
final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);
setupCustomContent(customPanel);
// 自定义内容视图区域
final View customTopPanel = customPanel.findViewById(R.id.topPanel);
final View customContentPanel = customPanel.findViewById(R.id.contentPanel);
final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);
final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);
final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);
final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);
setupContent(contentPanel);
setupButtons(buttonPanel);
setupTitle(topPanel);
final boolean hasCustomPanel = customPanel != null && customPanel.getVisibility() != View.GONE;
final boolean hasTopPanel = topPanel != null && topPanel.getVisibility() != View.GONE;
final boolean hasButtonPanel = buttonPanel != null && buttonPanel.getVisibility() != View.GONE;
if (!hasButtonPanel) {
if (contentPanel != null) {
final View spacer = contentPanel.findViewById(R.id.textSpacerNoButtons);
if (spacer != null) spacer.setVisibility(View.VISIBLE);
}
}
if (hasTopPanel) {
if (mScrollView != null) mScrollView.setClipToPadding(true);
}
if (!hasCustomPanel) {
final View content = mListView != null ? mListView : mScrollView;
if (content != null) {
final int indicators = (hasTopPanel ? ViewCompat.SCROLL_INDICATOR_TOP : 0) | (hasButtonPanel ? ViewCompat.SCROLL_INDICATOR_BOTTOM : 0);
setScrollIndicators(contentPanel, content, indicators, ViewCompat.SCROLL_INDICATOR_TOP | ViewCompat.SCROLL_INDICATOR_BOTTOM);
}
}
final ListView listView = mListView;
if (listView != null && mAdapter != null) {
listView.setAdapter(mAdapter);
final int checkedItem = mCheckedItem;
if (checkedItem > -1) {
listView.setItemChecked(checkedItem, true);
listView.setSelection(checkedItem);
}
}
}
//AlertController.AlertParams 持有AlertController的所有属性
//在调用builder里的设置属性方法时,就是给AlertController.AlertParams做一个缓存。
public static class AlertParams {
public final Context mContext;
public final LayoutInflater mInflater;
public int mIconId = 0;
public Drawable mIcon;
public int mIconAttrId = 0;
public CharSequence mTitle;
public View mCustomTitleView;
public CharSequence mMessage;
public CharSequence mPositiveButtonText;
...参数省略...
public AlertParams(Context context) {
mContext = context;
mCancelable = true;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
/**
* 最主要的方法是apply(),实际上就是把P中的参数挨个的设置到AlertController中, 也就是AlertDialog中的mAlert对象。从AlertDialog的各个setter方法中我们也可以看到,实际上也都是调用了mAlert对应的setter方法。
*/
public void apply(AlertController dialog) {
if (mCustomTitleView != null) {
dialog.setCustomTitle(mCustomTitleView);
} else {
if (mTitle != null)dialog.setTitle(mTitle);
if (mIcon != null)dialog.setIcon(mIcon);
if (mIconId != 0) dialog.setIcon(mIconId);
if (mIconAttrId != 0) dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
}
if (mMessage != null) dialog.setMessage(mMessage);
if (mPositiveButtonText != null) dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText, mPositiveButtonListener, null);
if (mNegativeButtonText != null)dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText, mNegativeButtonListener, null);
if (mNeutralButtonText != null) dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText, mNeutralButtonListener, null);
if ((mItems != null) || (mCursor != null) || (mAdapter != null))createListView(dialog);
if (mView != null) {
if (mViewSpacingSpecified)
dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, mViewSpacingBottom);
else
dialog.setView(mView);
} else if (mViewLayoutResId != 0)
dialog.setView(mViewLayoutResId);
}
}
}
在AlertDialog的Builder模式中并没有看到Director角色出现,并没按照标准的模式使用,而是做了一些修改,AlertDialog.Builder同时扮演了上下文提到的builder、ConcreteBuilder、Director的角色,简化了Builder模式的设计。
三、代理模式
代理(Proxy)模式提供了对目标对象另外的访问方式,即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上增强额外的功能操作,即扩展目标对象的功能。这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。
1)、UML:
- 共同接口:对客户端暴露出来的共同接口
- Target目标对象:从目标对象需要代理方法抽象出来的,其内部架构一般是不会暴露出来
- Proxy代理对象:持有目标对象的引用,客户端通过访问Proxy,来完成对Target的访问
2)、静态代理:这种方式可以做到在符合开闭原则的情况下对目标对象进行功能扩展。但是需要为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
//公共接口
public interface BuyHouse {
void buyHosue();
}
//目标对象 公共接口的实现类
public class BuyHouseImpl implements BuyHouse {
@Override
public void buyHosue() {
System.out.println("我要买房");
}
}
//代理对象 内部持有了目标对象
public class BuyHouseProxy implements BuyHouse {
private BuyHouse buyHouse;
public BuyHouseProxy(final BuyHouse buyHouse) {
this.buyHouse = buyHouse;
}
@Override
public void buyHosue() { //对目标对象的buyHosue方法进行了扩展
System.out.println("买房前准备");
buyHouse.buyHosue();
System.out.println("买房后装修");
}
}
//客户端通过访问代理对象来实现对目标对象的访问
public static void main(String[] args) {
BuyHouse buyHouse = new BuyHouseImpl();
BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse);
buyHouseProxy.buyHosue();
}
3)、动态代理:在动态代理中我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象由JDK再运行时为我们动态的来创建。相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。但是目标对象一定要实现接口,否则不能用动态代理。
//动态处理器
public class DynamicProxyHandler implements InvocationHandler {
private Object object;
public DynamicProxyHandler(final Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("买房前准备");
Object result = method.invoke(object, args);
System.out.println("买房后装修");
return result;
}
}
//客户端
//Proxy.newProxyInstance()方法接受三个参数:
//ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
//Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
//InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法
public static void main(String[] args) {
BuyHouse buyHouse = new BuyHouseImpl();
//由JDK的Proxy.newProxyInstance方法动态获取一个对象的代理对象
BuyHouse proxyBuyHouse = (BuyHouse) Proxy.newProxyInstance(
BuyHouse.class.getClassLoader(),
new Class[]{BuyHouse.class},
new DynamicProxyHandler(buyHouse));
//动态生成的代理对象调用接口的时候会触发InvocationHandler的invoke方法
proxyBuyHouse.buyHosue();
}
4)、Cglib代理:JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的类进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
//CGLIB代理类
public class CglibProxy implements MethodInterceptor {
private Object target;
public Object getInstance(final Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("买房前准备");
Object result = methodProxy.invoke(object, args);
System.out.println("买房后装修");
return result;
}
}
//客户端
public static void main(String[] args){
BuyHouse buyHouse = new BuyHouseImpl();
CglibProxy cglibProxy = new CglibProxy();
BuyHouseImpl buyHouseCglibProxy = (BuyHouseImpl) cglibProxy.getInstance(buyHouse);
buyHouseCglibProxy.buyHosue();
}
四、装饰模式
装饰模式又叫包装模式Wrapper,动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更灵活。同样上面的代理模式也是一种非继承的方式对类进行功能扩展,但他们之间也有不同之处。
1)、代理模式VS装饰模式:
- Proxy 模式:我想做,但不能做,我需要有一个能干的人来帮我做。
- Decorator模式:我想做,但不能做,我需要有各类特长的人来帮我做,但我有时只需要一个人,有时又需要很多人。
它们的区别就是,Proxy 模式需要的是一个能人,而 Decorator 模式需要的是一个团队。有些情况下,拥有了一个团队,会更加利于工作分工,而不至于将所有的事情,都让这个能人来干,他终将有一天会 hold 不住的。但有些情况下人多了反而不好,只需要一个能人就行了。
2)、代理模式:
代理模式是通过“组合”的方式对 GreetingImpl 进行包装,并对其进行功能扩展。这样,无需修改 GreetingImpl 的任何一行代码,就可以完成它想要做的事情。对目标对象进行扩展,其UML和CODE如下:
代理模式完美的实现了对目标对象的扩展,如下示例。但是要求在打印Before之外还想打印其他的呢,需求无止境,这个 Proxy 类将来可能会非常庞大,要干的事情会越来越多。一下子是日志记录,一下子是事务控制,还有权限控制,还有数据缓存。把所有的功能都放在这个 Proxy 类中是不明智的,同时这也违反了“开闭原则”。这时候就需要装饰模式来解决这个问题了。
//公共接口 有时可以省略
public interface Greeting {
void sayHello(String name);
}
//目标对象 只能打印Hello 不能打印其他的东西
public class GreetingImpl implements Greeting {
@Override
public void sayHello(String name) {
System.out.println("Hello! " + name);
}
}
//代理对象 除了能打印Hello 还能打印一个Before出来
public class GreetingProxy implements Greeting {
private GreetingImpl greetingImpl;
public GreetingProxy(GreetingImpl greetingImpl) {
this.greetingImpl = greetingImpl;
}
@Override
public void sayHello(String name) {
before();
greetingImpl.sayHello(name);
}
private void before() {
System.out.println("Before");
}
}
3)、装饰模式:
装饰模式搞了一个抽象类 GreetingDecorator出来,它就是传说中的“装饰器”了,也实现了 Greeting接口(与Proxy模式相同),但是在装饰器中不是组合实现类 GreetingImpl,而是组合它的接口 Greeting;通过两个 Decorator 的实现类(也就是具体装饰器),来提供多种功能的扩展。
GreetingDecorator 只是一个抽象的装饰器,要想真正使用它,您得去继承它,实现具体的装饰器才行。在具体装饰器的构造方法中调用了父类的构造方法,也就是把 Greeting 实例射进去了。在具体装饰器中,完成自己应该完成的事情。真正做到了各施其责,而不是一人包揽。先 new GreetingImpl,再 new GreetingBefore,最后 new GreetingAfter。一层裹一层,就像洋葱一样!但不同的是,裹的顺序是可以交换,比如,先 new GreetingAfter,再 new GreetingBefore。
//公共接口
public interface Greeting {
void sayHello(String name);
}
//目标对象 只能打印Hello 不能打印其他的东西
public class GreetingImpl implements Greeting {
@Override
public void sayHello(String name) {
System.out.println("Hello! " + name);
}
}
//抽象的装饰类 持有了公共接口的引用
public abstract class GreetingDecorator implements Greeting {
private Greeting greeting;
public GreetingDecorator(Greeting greeting) {
this.greeting = greeting;
}
@Override
public void sayHello(String name) {
greeting.sayHello(name);
}
}
//第一个具体的装饰类 除了能打印Hello 还能打印Before
public class GreetingBefore extends GreetingDecorator {
public GreetingBefore(Greeting greeting) {
super(greeting);
}
@Override
public void sayHello(String name) {
before();
super.sayHello(name);
}
private void before() {
System.out.println("Before");
}
}
//第二个具体的装饰类 除了能打印Hello 还能打印After
public class GreetingAfter extends GreetingDecorator {
public GreetingAfter(Greeting greeting) {
super(greeting);
}
@Override
public void sayHello(String name) {
super.sayHello(name);
after();
}
private void after() {
System.out.println("After");
}
}
//客户端 将两个具体的装饰类包装了进行,最后拿到的接口对象除了能够打印Hello还能打印Before还能打印After
public static void main(String[] args) {
Greeting greeting = new GreetingAfter(new GreetingBefore(new GreetingImpl()));
greeting.sayHello("Jack");
}
4)、两种模式的区别:这里两个模式都是对类的包装,在不改变类自身的情况下,为其添加特定的功能。若这些功能比较单一,可考虑使用 Proxy 模式,但对于功能较多且需动态扩展的情况下,您不妨尝试一下 Decorator 模式吧!装饰模式还能对一个对象进行多次装饰,通过使用不同的具体装饰类进行不同的排列组合。
5)、装饰模式的应用IO流:想要读取一个二进制文件,可以获取这样的输入流
InputStream input = new DataInputStream(new BufferedInputStream(new FileInputStream("C:/test.exe")));
6)、装饰模式的应用Context:
ContextWrapper就是android里面的一个经典的包装类。ContextWrapper里面有一个Context类型的成员变量mBase,当然它实际的类型是ContextImpl,ContextWrapper实现方法的时候调用了mBase的方法,其源码如下:
public class ContextWrapper extends Context {
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
protected void attachBaseContext(Context base) {
if (mBase != null) throw new IllegalStateException("Base context already set");
mBase = base;
}
public Context getBaseContext() {
return mBase;
}
@Override
public AssetManager getAssets() {
return mBase.getAssets();
}
@Override
public Resources getResources(){
return mBase.getResources();
}
@Override
public PackageManager getPackageManager() {
return mBase.getPackageManager();
}
@Override
public ContentResolver getContentResolver() {
return mBase.getContentResolver();
}
@Override
public Looper getMainLooper() {
return mBase.getMainLooper();
}
ContextWrapper继承自了Context ,Context 就相当于装饰模式中的公共接口,当然这里Context太复杂了抽象了一些公共的方法出来,并且主要有ContextImpl实现类完成,ContextWrapper刚好持有了ContextImpl的引用而进行装饰,其源码如下:
class ContextImpl extends Context {
@Override
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
String[] receiverPermissions = receiverPermission == null ? null : new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, options, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
final int targetSdkVersion = getApplicationInfo().targetSdkVersion;
mMainThread.getInstrumentation().execStartActivity( getOuterContext(),mMainThread.getApplicationThread(), null, (Activity) null, intent, -1, options);
}
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
...省略代码...
}
ContextImpl实现了Context的所有方法,避免代码重复,将一些通用的方法如starActivity()放到ContextImpl中,避免Activity,Application,Service中重复代码。Activity、Service、Application都是ContextWrapper的子类。其继承关系图如下:
Android通过对装饰模式,对ContextWrapper的不同子类,构建了一个庞大的Context家族。Activity、Service、Application等都是这个家族的成员,但他们又各不相同。因此可以理解装饰模式是对同家族成员的一种包装,而适配器模式是对不同家族成员的一种统一。
五、适配器模式
将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器Wrapper
1)、UML结构图:
- Target目标角色:接口,客户需要的用到的方法或者接口
- Adaptee源角色:已有实现类
- Adapter适配器:能够将源角色转换成目标角色
2)、通用代码:
- 类适配器:Adapter适配器实现了Target,并通过继承Adaptee方式将源角色转换成目标角色
public interface ClassTarget{
public void sampleOperation2(); //源角色ClassAdaptee没有的方法
}
public class ClassAdaptee{
public void sampleOperation1(){ } //源角色ClassAdaptee希望被转换的方法
}
//类适配器继承了ClassAdaptee并实现了ClassTarget
public class ClassAdapter extends ClassAdaptee implements ClassTarget{
public void sampleOperation2(){
sampleOperation1(); //相关代码,可以作一些逻辑处理,将sampleOperation1方法转换成sampleOperation2
}
}
- 对象适配器:Adapter适配器实现了Target,但不是通过继承而是通过委派关系连接到Adaptee
public interface ClassTarget{
public void sampleOperation2(); //源角色ClassAdaptee没有的方法
}
public class ClassAdaptee{
public void sampleOperation1(){ } //源角色ClassAdaptee希望被转换的方法
}
//类适配器持有ClassAdaptee的引用并实现了ClassTarget
public class ClassAdapter implements ClassTarget{
private ClassAdaptee adaptee;
public ClassAdapter(ClassAdaptee adaptee){
this.adaptee=adaptee;
}
public void sampleOperation2(){
adaptee.sampleOperation1(); //可以作一些逻辑处理,通过委托方式sampleOperation1方法转换成sampleOperation2
}
}
3)、两种适配器比较:
- 类适配器使用对象继承的方式,是静态定义;对象适配器使用对象组合的方式,是动态组合
- 类适配器可以重新定义Adaptee的部分行为;对象适配器重新定义行为很难
- 类适配器仅仅引入了一个对象;对象适配器需要额外的引用来间接得到Adaptee
- 对象适配器能够把多种源适配到同一个目标
4)、ListView源码解析:
ListView为什么要使用Adapter模式呢? 我们知道,作为最重要的View,ListView需要能够显示各式各样的视图,每个人需要的显示效果各不相同,显示的数据类型、数量等也千变万化。通过代理数据集来告知ListView数据的个数( getCount函数 )以及每个数据的类型( getItem函数 ),最重要的是要解决Item View的输出。Item View千变万化,但终究它都是View类型,Adapter统一将Item View输出为View ( getView函数 ),这样就很好的应对了Item View的可变性。
public abstract class BaseListAdapter<T> extends BaseAdapter{
protected List<T> dataList; //当前数据源
public BaseListAdapter(){
super();
}
public BaseListAdapter(List<T> data) {
super();
this.dataList=data;
}
public void setDataList(List<T> data){
this.dataList=data;
}
@Override
public int getCount() {
if(dataList==null) return 0;
else return dataList.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public abstract View getView(int position, View convertView, ViewGroup parent);
// {
// BaseHolder holder;
// if (convertView == null) {
// holder=new BaseHolder(getActivityThis());
// convertView=holder.getView();
// convertView.setTag(holder);
// }else {
// holder = (BaseHolder)convertView.getTag();
// }
// try {
// }catch (Exception e){
// }
// return holder.getView();
// }
}
ListView继承自AbsListView,Adapter定义在AbsListView中,起源吗如下:
public abstract class AbsListView extends AdapterView<ListAdapter> implements
TextWatcher,ViewTreeObserver.OnGlobalLayoutListener,Filter.FilterListener,
ViewTreeObserver.OnTouchModeChangeListener,
RemoteViewsAdapter.RemoteAdapterConnectionCallback {
//AbsListView持有了Adapter
ListAdapter mAdapter ;
@Override
protected void onAttachedToWindow() { //关联到Window时调用的函数
super.onAttachedToWindow();
if (mAdapter != null && mDataSetObserver == null) { //观察者模式
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
mDataChanged = true;
mOldItemCount = mItemCount;
//适配器模式 获取Item的数量,调用的是mAdapter的getCount方法
mItemCount = mAdapter.getCount();
}
mIsAttached = true;
}//子类需要覆写layoutChildren来布局child view也就是Item View
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
mInLayout = true;
if (changed) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) getChildAt(i).forceLayout();
mRecycler.markChildrenDirty();
}
if (mFastScroller != null && mItemCount != mOldItemCount)
mFastScroller.onItemCountChanged(mOldItemCount, mItemCount);
layoutChildren(); // 布局Child View
mInLayout = false;
mOverscrollMax = (b - t) / OVERSCROLL_LIMIT_DIVISOR;
}//获取一个Item View
View obtainView(int position, boolean[] isScrap) {
isScrap[0] = false;
View scrapView;
scrapView = mRecycler.getScrapView(position);//从缓存的Item View中获取 复用机制
View child;
if (scrapView != null) {
//适配器模式 获取Item View视图,调用的是mAdapter的getView方法
child = mAdapter.getView(position, scrapView, this);
} else {
child = mAdapter.getView(position, null, this);
}
return child;
}
}
AbsListView定义了集合视图的框架,比如Adapter模式的应用、复用Item View的逻辑、布局Item View的逻辑等。子类只需要覆写特定的方法即可实现集合视图的功能,例如ListView的源码如下:
public class ListView extends AbsListView{
@Override
protected void layoutChildren() {
...省略代码...
super.layoutChildren();
invalidate();
// 根据布局模式来布局Item View
switch (mLayoutMode) {
case LAYOUT_SET_SELECTION:
if (newSel != null) sel = fillFromSelection(newSel.getTop(),childrenTop, childrenBottom);
else sel = fillFromMiddle(childrenTop, childrenBottom);
break;
case LAYOUT_SYNC:
sel = fillSpecific(mSyncPosition, mSpecificTop);
break;
case LAYOUT_FORCE_BOTTOM:
sel = fillUp(mItemCount - 1, childrenBottom);
adjustViewsUpOrDown();
break;
case LAYOUT_FORCE_TOP:
mFirstPosition = 0;
sel = fillFromTop(childrenTop);
adjustViewsUpOrDown();
break;
case LAYOUT_SPECIFIC:
sel = fillSpecific(reconcileSelectedPosition(), mSpecificTop);
break;
case LAYOUT_MOVE_SELECTION:
sel = moveSelection(oldSel, newSel, delta, childrenTop, childrenBottom);
break;
default:
break;
}
}
//从上到下填充Item View
private View fillDown(int pos, int nextTop) {
View selectedView = null;
int end = (mBottom - mTop);
if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK)
end -= mListPadding.bottom;
while (nextTop < end && pos < mItemCount) {
boolean selected = pos == mSelectedPosition;
View child = makeAndAddView(pos, nextTop, true, mListPadding.left, selected);
nextTop = child.getBottom() + mDividerHeight;
if (selected) selectedView = child;
pos++;
}
return selectedView;
}
//添加Item View
private View makeAndAddView(int position, int y, boolean flow, int childrenLeft, boolean selected) {
View child;
child = obtainView(position, mIsScrap);
setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);
return child;
}
}
ListView覆写了AbsListView中的layoutChilden函数,在该函数中根据布局模式来布局Item View。Item View的个数、样式都通过Adapter对应的方法来获取,获取个数、Item View之后,将这些Item View布局到ListView对应的坐标上,再加上Item View的复用机制,整个ListView就基本运转起来了。
这里的Adapter并不是经典的适配器模式,但是却是对象适配器模式的优秀示例,也很好的体现了面向对象的一些基本原则。这里的Target角色和Adapter角色融合在一起,Adapter中的方法就是目标方法;而Adaptee角色就是ListView的数据集与Item View,Adapter代理数据集,从而获取到数据集的个数、元素。
六、外观模式
外观模式又叫做门面模式,主要目的在于让外部减少与子系统内部多个模块的交互,从而让外部能够更简单的使用子系统。它负责把客户端的请求转发给子系统内部的各个模块进行处理。
1)、UML结构图:
- Facade:外观类,为调用方定义出来的简单接口,客户端只需要Facade公开的简单接口调用就行了不用知道系统内部交互。一般用单例模式来保证Facade只有一个,在一些简单的场景也可以用组合的方式代替接口。
- Module:子模块类,功能提供者或者是一个复杂系统的子模块,客户端完全没必要知道子模块的存在,由外观类代理就行了
2)、通用代码:
//公共接口 有时候可以省略
public interface FInterface {
void initSystem(); //初始化系统
void powerOn(); //开机
}
//子模块1
public class ModuleCPU implements FInterface{
@Override
public void initSystem() {
Log.e("TEST","CPU 初始化");
}
@Override
public void powerOn() {
Log.e("TEST","CPU 启动");
}
}
//子模块2 可以有无数个子模块
public class ModuleRAM implements FInterface{
@Override
public void initSystem() {
Log.e("TEST","内存 初始化");
}
@Override
public void powerOn() {
Log.e("TEST","内存 启动");
}
}
//外观类Facade 可以实现公用接口 也可以简单点不实现 客户端访问只需要知道Computer就行了
public class Computer{
private static Computer computer=new Computer();
private ModuleCPU cpu;
private ModuleRAM ram;
public static Computer getInstance(){ //通常情况一个复杂的系统只有一个 没有规定必须用单例模式
return computer;
}
private Computer(){
cpu=new ModuleCPU();
ram=new ModuleRAM();
}
//通过代理方式或者自由组合逻辑,给客户端一个简单的调用方法
public void startComputer(){
ram.initSystem();
cpu.initSystem();
ram.powerOn();
cpu.powerOn();
}
}
public static void main(String[] args) {
Computer.getInstance().startComputer();//客户端不需要知道ram/cpu等子模块具体复杂的操作
}
总结:Facade外观类封装了各个模块交互的过程,如果今后内部模块调用关系发生了变化,只需要修改Facade实现就可以了;外观类是可以被多个客户端进行调用的。
3)、外观模式VS代理模式VS适配器模式:
- 代理模式 Proxy:为其他对象提供一种代理以控制对这个对象的访问
- 适配器模式 Adpater:将一个类的接口转换成客户希望的另外一个接口,使得原本接口不兼容而不能一起工作的那些类可以一起工作
- 外观模式 Facade:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
代理模式和适配器模式应该说很相像,但是他们的区别也很明显,代理模式和被代理者的接口是同一个,只是使用中客户访问不到被代理者,所以利用代理间接的访问,而适配器模式,是因为接口不同,为了让用户使用到统一的接口,把原先的对象通过适配器让用户统一的使用,大多数运用在代码维护的后期,或者借用第三方库的情况下 ,而外观模式,是大家经常无意中使用的,就是把错综复杂的子系统关系封装起来,然后提供一个简单的接口给客户使用,就类似于一个转接口,可以想象成一个漏斗,中间细的那一段,越细耦合度越低,外观模式就是为了降低耦合度。
七、策略模式
策略模式,定义一系列的算法,把它们一个个封装起来,并且是他们可相互替换,使得算法可独立于使用它的客户而变化。一个类定义了多种行为,并且这些行为在这个类的方法中以多个条件语句的形式出现,那么可以使用策略模式避免在类中使用大量的条件语句。
1)、UML结构图:
- Context:策略上下文,负责和具体的策略实现交互,通常策略上下文对象会持有一个真正的策略实现对象,策略上下文还可以让具体的策略实现从其中获取相关数据,回调策略上下文对象的方法。
- Stragety:策略接口,用来约束一系列具体的策略算法, 策略上下文角色使用此策略接口来调用具体的策略所实现算法。
- ConcreteStrategy:具体策略的实现,即具体的算法实现。
2)、通用代码:
//策略接口
public interface HRzonesALG{
float getHeartInterValue(int bmp); //获取心率强度值
}
//具体策略 最大心率算法
public class MHRZonesALG implements HRzonesALG{
@Override
public float getHeartInterValue(int bmp) {
float inter = ((float) bmp) / userMaxbmp;
inter= ToolMath.getRoundMath(inter, 3);
return inter;
}
}
//具体策略 静态心率算法
public class SHRZonesALG implements HRzonesALG{
@Override
public float getHeartInterValue(int bmp) {
int tempBmp = bmp - userStaticBmp;
if (tempBmp < 0) tempBmp = 0;
float inter = ((float) tempBmp) / ((float) (userMaxbmp - userStaticBmp));
inter = ToolMath.getRoundMath(inter, 3);
return inter;
}
}
//客户端只需要持有策略接口就可以根据实际情况进行算法访问
public static void main(String[] args) {
HRzonesALG hrALG;
switch (GymSCLApplication.getSchoolHrAlg()){
case MHRZonesALG.HEART_METHOD_MAXBMP:
hrALG=new MHRZonesALG();
break;
case SHRZonesALG.HEART_METHOD_STABMP:
hrALG=new SHRZonesALG();
break;
default:
hrALG=new MHRZonesALG();
break;
}
hrALG.getHeartInterValue();//获取心率强度
}
3)、Volley源码中对策略模式的应用:
八、状态模式
当一个对象的内在状态改变时允许改变其行为 这个对象看起来是改变了其类(状态模式的行为时平行的,不可替换的)。使用状态模式同样避免在类中使用大量的条件语句。
1)、UML结构图:
九、模板模式
模板模式是通过定义一个算法骨架,而将算法中的步骤延迟到子类,这样子类就可以复写这些步骤的实现来实现特定的算法。当多个子类有公有的方法,并且逻辑基本相同,可以吧这些重要的复杂的算法,设计成为模板方法。这种方式经常用来代码重构。
1)、UML结构图:定义一个模板结构,将具体内容延迟到子类去实现。
2)、通用代码:
//这是一个模板 子类去实现具体的方法内容
public abstract class BaseActivity extends Activity{
protected boolean isDestory=false;
/** 获取类名*/
protected String getActivityName(){
return this.getClass().getName();
}
/** 获取实例*/
protected Activity getActivityThis(){
return this;
}
/** 是否全屏模式*/
protected abstract boolean isFullScreenStyle();
/** 视图初始化*/
protected abstract void initView();
/** 数据初始化*/
protected abstract void initData();
/** 业务初始化*/
protected abstract void initBusiness();
protected void initBundle(Bundle savedInstanceState){}
protected void initBundle(Intent savedIntent){}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isDestory=false;
ToolDebug.printLogE("BASE",getActivityThis(),"onCreate");
initConfig();
if(savedInstanceState!=null)
initBundle(savedInstanceState);
else
initBundle(getIntent());
initView();
initData();
initBusiness();
}
protected void initConfig(){
if(isFullScreenStyle()){
//设置永不休眠模式
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//隐藏系统工具栏
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
}
}
}
3)、AsyncTask源码解析:
public abstract class AsyncTask<Params, Progress, Result> {
//父类已经定义好的方法 子类需要实现或者重新完成自己所需的功能
protected abstract Result doInBackground(Params... params);
protected void onPreExecute() {
}
@SuppressWarnings({"UnusedDeclaration"})
protected void onPostExecute(Result result) {
}
@SuppressWarnings({"UnusedDeclaration"})
protected void onProgressUpdate(Progress... values) {
}
protected void onCancelled() {
}
//构造函数初始化了mWorker 和mFuture
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//步骤2:异步任务里面最终执行的doInBackground
//步骤4:并将结果作为参数执行了postResult
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
//步骤3:执行过程中 发送更新进度消息
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()", e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
//内部维护了一个Handler 固定了几个方法给子类去实现
private static final InternalHandler sHandler = new InternalHandler();
public static void init() {
sHandler.getLooper();
}
private static class InternalHandler extends Handler {
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult result = (AsyncTaskResult) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
//任务执行完成 在UI线程操作 子类复写或实现相应功能
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
//任务执行过程中 在UI线程操作 子类复写或实现相应功能
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
//步骤5:任务结束 根据任务状态调用onCancelled或onPostExecute
private void finish(Result result) {
if (isCancelled())
onCancelled(result);
else
onPostExecute(result);
mStatus = Status.FINISHED;
}
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) postResult(result);
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));
message.sendToTarget(); //发送执行结果给Handler
return result;
}
//异步任务执行 启动线程池
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:" + " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:" + " the task has already been executed " + "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
//步骤1:执行任务前准备 在UI线程 子类复写或实现实现相应功能
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture); //执行线程mFuture 内部有一个mWorker
return this;
}
}
十、观察者模式:
观察者模式定义了对象之间的一对多的依赖关系,这样,当"一"的一方状态发生变化时,它所依赖的"多"的一方都会收到通知并且自动更新
1)、UML结构图:
- 抽象主题Subject:被观察的一方,也就是定义中的“一”的方,它的数据更改后能够通知别人
- 抽象观察者Observer:观察者一方,也就是定义中的“多”的方,一般用来监听主题的对象
- 具体主题:被监听的具体数据或对象,继承抽象主题。内部应该拥有一个所有观察者的集合
- 具体观察者:监听对象,继承抽象观察者
2)、普通观察者代码:
//抽象主题 可以是接口或者抽象类
interface Subject {
void addObserver(Observer obj); //添加观察者
void deleteObserver(Observer obj); //移除观察者
void notifyObserver(); //当主题方法改变时,这个方法被调用,通知所有的观察者
}
//抽象观察者
interface Observer {
public void update(String info);//当主题状态改变时,会调用该方法,每个观察者都需要实现该方法
}
//具体主题
public class TeacherSubject implements Subject {
//内部维护了一个观察者集合 用来存放和记录观察者
private List<Observer> observers=new ArrayList<Observer>();
private String info;
@Override
public void addObserver(Observer obj) { //实现了添加观察者方法
observers.add(obj);
}
@Override
public void deleteObserver(Observer obj) { //实现了移除观察者方法
int i = observers.indexOf(obj);
if(i>=0)observers.remove(obj);
}
@Override
public void notifyObserver() { //通知所有观察者方法
for(int i=0;i<observers.size();i++){
Observer o=(Observer)observers.get(i);
o.update(info);
}
}
public void setHomework(String info){
this.info=info;
System.out.println("今天的作业是"+info);
this.notifyObserver();
}
}
//具体观察者
public class StudentObserver implements Observer {
//保存一个Subject的引用,以后如果可以想取消订阅,有了这个引用会比较方便
private TeacherSubject t;
private String name;
public Student(String name,Teacher t) {
this.name=name;
this.t = t;
t.addObserver(this); //注册观察者对象
}
@Override
public void update(String info) {
System.out.println(name+"得到作业:"+info);
}
}
3)、JAVA内置观察者模式:
在java.util包中包含有基本的Observer接口和Observable抽象类,功能上和Subject接口和Observer接口类似。使用上,就方便多了,因为许多功能比如说注册,删除,通知观察者的那些功能已经内置好了。源码如下:
package java.util;
public interface Observer {
void update(Observable o, Object arg);
}
package java.util;
public class Observable {
private boolean changed = false;
private Vector obs; //所有观察者集合 这个集合是一个线程安全集合
public Observable() {
obs = new Vector();
}
//添加一个观察者(订阅者),已经存在则不再重复添加 支持多线程
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
//删除一个观察者(订阅者Subscribe) 支持多线程
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
//通知观察者(订阅者Subscribe)
public void notifyObservers() {
notifyObservers(null);
}
//通知观察者(订阅者Subscribe) 带参数
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) { //线程安全
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
//删除所有观察者(订阅者Subscribe)
public synchronized void deleteObservers() {
obs.removeAllElements();
}
//变更标识
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
- 如何使对象变成观察者:实现观察者接口(java.util.Observer),然后调用Observable对象的addObserver()方法.不想再当观察者时,调用deleteObserver()就可以了
- 主题如何发送通知:先调用setChanged()方法,在调用notifyObservers()方法或者notifyObservers(Object arg)。如果调用的没有参数方法进行通知,那么就需要具体观察者在update方法里面通过参数O进行主动拉取;如果调用的有参数方法进行通知,那么主题可以推送任意一个对象具体观察者在update方法里面通过参数arg就能获取到。
//具体主题只需要继承Observable
public class Teacher extends Observable {
private String info;
public void setHomework(String info) {
this.info=info;
System.out.println("布置的作业是"+info);
setChanged(); //标识状态已经改变的事实
notifyObservers(); //通知所有观察者
//也可以调用带参数的notifyObservers(Object arg) 传递一个Object给所有的观察者
}
public String getInfo() {
return info;
}
}
//具体观察者
public class Student implements Observer{
private Observable ob;
private String name;
public Student(String name,Observable ob) {
this.ob = ob;
this.name=name;
ob.addObserver(this);
}
@Override
public void update(Observable o, Object arg) { //实现此方法 用来接收主题发起的更新通知
Teacher t=(Teacher)o; //参数O就是主题对象,参数arg是主题对象notifyObservers的参数
System.out.println(name+"得到作业信息:"+t.getInfo());
}
}
4)、观察者模式优缺点:
观察者模式提供了一种对象设计,让主题和观察者之间耦合度降得很低,为什么呢?关于观察者的一切,主题只知道观察者实现了Observer接口,并不需要观察者具体的类是谁,做了什么或者其他细节。这样的话,由于松耦合,改变主题或者观察者其中一方,并不会影响另一方,只要他们之间的接口仍被遵守,就可以自由地改变它。降低对象之间的耦合度,也是面设对象设计的一个很重要的原则。
5)、Android中的回调模式:例如给按键设置监听器等方式其实也是观察者模式的应用
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
...省略代码...
public interface OnClickListener { //监听器接口 定义观察者
void onClick(View v);
}
...省略代码...
ListenerInfo mListenerInfo; //监听器的引用
ListenerInfo getListenerInfo() {
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
...省略代码...
public void setOnClickListener(OnClickListener l) { //设置监听器 管理主题与观察者
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
...省略代码...
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
...省略代码...
if (!mHasPerformedLongPress) {
removeLongPressCallback();
if(!focusTaken){
if (mPerformClick == null)mPerformClick = new PerformClick();
if (!post(mPerformClick)) performClick();
}
}
...省略代码...
}
}
public boolean performClick() {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this); //调用回调接口
return true;
}
return false;
}
}
十一、责任链模式:
责任链就是有一个请求需要多个对象来进行处理,将这些对象做成一条链,但具体由哪个对象来处理吗,根据条件判断来确定,如果不能处理会传递给链中的下一个对象,直到有对象处理它为止。
1)、使用场景:
- 有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行的时候再确定。例如View的事件分发机制
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
- 可动态的指定一组对象处理请求,客户端可以动态创建责任链来处理请求。例如Okhttp的拦截器
2)、UML结构图:
- 抽象处理者Handler:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- 具体处理者Concrete Handler:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类Client:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
3)、通用代码:
/抽象处理者角色
abstract class Handler{
private Handler next; //链表方式将处理者做成一条链
public void setNext(Handler next){
this.next=next;
}
public Handler getNext(){
return next;
}
public abstract void handleRequest(String request); //处理请求的方法
}
//具体处理者角色1
class ConcreteHandler1 extends Handler{
public void handleRequest(String request) {
if(request.equals("one"))
System.out.println("具体处理者1负责处理该请求!");
else
if(getNext()!=null)
getNext().handleRequest(request);
else
System.out.println("没有人处理该请求!");
}
}
//具体处理者角色2
class ConcreteHandler2 extends Handler{
public void handleRequest(String request){
if(request.equals("two"))
System.out.println("具体处理者2负责处理该请求!");
else
if(getNext()!=null)
getNext().handleRequest(request);
else
System.out.println("没有人处理该请求!");
}
}
//客户端
public static void main(String[] args){
//组装责任链
Handler handler1=new ConcreteHandler1();
Handler handler2=new ConcreteHandler2();
handler1.setNext(handler2);
//提交请求
handler1.handleRequest("two");
}
4)、在Java/Android中的应用:
- try-catch语句
- Ordered Broadcast
- ViewGroup/View的事件传递,用树的方式将责任链起来,事件通过树的方式层层传递直到消费了为止
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
...省略代码...
if (onFilterTouchEventForSecurity(ev)) {
final int action = ev.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
//处理第一个DOWN事件按下
if (actionMasked == MotionEvent.ACTION_DOWN) {
cancelAndClearTouchTargets(ev);
resetTouchState();
}
//检查是否进行了拦截
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev); //调用onInterceptTouchEvent来判断是否进行了拦截
ev.setAction(action);
} else {
intercepted = false;
}
} else {
intercepted = true;
}
...省略代码...
if (!canceled && !intercepted) { //当前事件没有被拦截
...省略代码...
final int childrenCount = mChildrenCount;
if (childrenCount != 0) {
//遍历子控件,寻找一个可以接收当前事件的子控件
final View[] children = mChildren;
final float x = ev.getX(actionIndex);
final float y = ev.getY(actionIndex);
final boolean customOrder = isChildrenDrawingOrderEnabled();
for (int i = childrenCount - 1; i >= 0; i--) {
...省略代码...
//分发事件给子控件
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
//子控件想处理当前事件 mLastTouchDownTime = ev.getDownTime();
mLastTouchDownIndex = childIndex;
mLastTouchDownX = ev.getX();
mLastTouchDownY = ev.getY();
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
}
}
...省略代码...
}
}
if (mFirstTouchTarget == null) {
//没有子控件进行处理当前事件,自己进行处理,参数为null
handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS);
}
...省略代码
return handled;
}
//参数child不为null将事件分发给子控件 child为null调用父类dispatchTouchEvent方法
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, View child, int desiredPointerIdBits) {
final boolean handled;
final int oldAction = event.getAction();
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
if (child == null) {
handled = super.dispatchTouchEvent(event); //调用父类dispatchTouchEvent,因为ViewGroup继承View,因此自己进行事件的处理
} else {
handled = child.dispatchTouchEvent(event); //调用子控件的dispatchTouchEvent,子控件进行事件的处理
}
event.setAction(oldAction);
return handled;
}
...代码省略...
}
//ViewGroup的onInterceptTouchEvent默认返回false,不进行事件的拦截
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
- Okhttp的拦截器,动态的创建了一组对象来处理请求
//Okhttp里面的源码
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>(); //构建拦截器
interceptors.addAll(client.interceptors()); //用户添加的应用拦截器
interceptors.add(new RetryAndFollowUpInterceptor(client)); //主要负责重定向和重试
//桥接网络层和应用层用主要包含:将用户的request,转变为网络层的request,比如添加各种请求头/UA/Cookie/Content-Type等;
//将网络层的response转变为用户层的response,比如解压缩,除去各种请求头
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));//缓存处理
interceptors.add(new ConnectInterceptor(client)); //建立连接
if (!forWebSocket)interceptors.addAll(client.networkInterceptors());//网络连接器
interceptors.add(new CallServerInterceptor(forWebSocket)); //请求服务端
//通过链式请求的得到response
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0, originalRequest, this, client.connectTimeoutMillis(), client.readTimeoutMillis(), client.writeTimeoutMillis());
IOException ioException = null;
try {
return chain.proceed(originalRequest); //责任链模式进行依次处理上面添加的拦截器
} catch (IOException e) {
ioException = e; throw e;
} finally {
transmitter.noMoreExchanges(ioException);
}
}
}