在线目录生成工具

目录

0.前言

个人学习、整理和记录设计模式相关知识点用。其中大部分内容来自以下地址,表示感谢。
cyc-设计模式
菜鸟教程-设计模式
Android中竟然包含这么多设计模式,一起来学一波!
Android的设计模式
参考书籍:《设计模式-可复用面向对象软件的基础》

1.定义

设计模式代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用,是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。是解决问题的方案,学习现有的设计模式可以做到经验的复用。拥有设计模式词汇,在沟通时就能用更少的词汇来讨论,并且不需要了解底层细节。

2.分类

主要介绍《设计模式-可复用面向对象软件的基础》书中提出的23种模式。
按照目的不同,可以把设计模式分为三大类,创建型、结构型、行为型。
创建型模式与对象的创建有关;
结构型模式处理类或对象的组合;
行为型模式对类或对象怎样交互和怎样分配职责进行描述。

创建型模式

单例模式(Singleton Pattern)、工厂模式(Factory Pattern)、抽象工厂模式(Abstract Factory Pattern)、建造者模式(Builder Pattern)、原型模式(Prototype Pattern)。

结构型模式

适配器模式(Adapter Pattern)、桥接模式(Bridge Pattern)、组合模式(Composite Pattern)、装饰器模式(Decorator Pattern)、外观模式(Facade Pattern)、享元模式(Flyweight Pattern)、代理模式(Proxy Pattern)。

行为模式

责任链模式(Chain of Responsibility Pattern)、命令模式(Command Pattern)、解释器模式(Interpreter Pattern)、迭代器模式(Iterator Pattern)、中介者模式(Mediator Pattern)、备忘录模式(Memento Pattern)、观察者模式(Observer Pattern)、状态模式(State Pattern)、策略模式(Strategy Pattern)、模板方法模式(Template Pattern)。

3.创建型模式

这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用new运算符直接实例化对象,这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

3.1 单例模式(Singleton Pattern)

3.1.1 模式描述

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
适用性:以下情况可以使用单例模式
1.当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时;
2.当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

3.1.2 代码实现

// 双重校验锁实现单例模式
public class Singleton {
    private static Singleton instance;

    public static Singleton getInstance(Object obj) {
        Singleton tem = instance;
        if (tem == null) {
            synchronized (Singleton.class) {
                if (tem == null) {
                    instance = tem = new Singleton(obj);
                }
            }
        }
        return tem;
    }

    final private Object params;

    private Singleton(Object params) {
        this.params = params;
    }

    public void doSomething() {
        System.out.println(params);
    }
}


//枚举实现单例模式
public enum Singleton2 {
    INSTANCE("def");

    final private Object params;

    Singleton2(Object params) {
        this.params = params;
    }

    public void doSomething() {
        System.out.println(params);
    }
}

上诉代码中,双重校验锁实现方式,可以用反射破坏单例,代码如下

Singleton.getInstance("name11111").doSomething();
        
        try {
            //反射破坏单例模式
            Class clz = Class.forName("com.perdev.designpattern.singleton.java.Singleton");
            Constructor<Singleton> constructor = clz.getDeclaredConstructor(Object.class);
            //Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor(Object.class);

            constructor.setAccessible(true);
            Singleton singleton = constructor.newInstance("reflect");
            singleton.doSomething();

        } catch (Exception e) {
            d("e=" + e.toString());
        }

而枚举实现方式,不可用反射破坏,原因可以看这里

github 代码地址

3.1.3 android源码中的单例模式

android.util.Singleton

/**
 * Singleton helper class for lazily initialization.
 *
 * Modeled after frameworks/base/include/utils/Singleton.h
 *
 * @hide
 */
public abstract class Singleton<T> {

    @UnsupportedAppUsage
    public Singleton() {
    }

    @UnsupportedAppUsage
    private T mInstance;

    protected abstract T create();

    @UnsupportedAppUsage
    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

这是android源码framwork包下的一个抽象类,支持泛型,从而支持模板化的形式创建任意类型对象的单例。
具体使用:在ActivityManager类中,有如下的使用

 /**
     * @hide
     */
    @UnsupportedAppUsage
    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }


     @UnsupportedAppUsage
    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

EventBus也使用了单例


static volatile EventBus defaultInstance;

  /** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
        EventBus instance = defaultInstance;
        if (instance == null) {
            synchronized (EventBus.class) {
                instance = EventBus.defaultInstance;
                if (instance == null) {
                    instance = EventBus.defaultInstance = new EventBus();
                }
            }
        }
        return instance;
    }
    

3.2 工厂模式(Factory Pattern)

3.2.1 模式描述

意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。使得类的实例化延迟到其子类。
适用性:以下情况使用单例模式:
1.当一个类不知道它所必须创建的对象的类的时候。
2.当一个类希望由它的子类来指定它所创建的对象的时候。

3.2.2 代码实现


public interface Shape {
    void draw();
}


public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("draw a circle.");
    }
}


public class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("draw a square.");
    }
}


public class ShapeFactory {
    public static final int SHAPE_CIRCLE = 0;
    public static final int SHAPE_SQUARE = 1;

    public static Shape getShape(int shapeType) {
        if (SHAPE_CIRCLE == shapeType) {
            return new Circle();
        } else if (SHAPE_SQUARE == shapeType) {
            return new Square();
        }
        return null;
    }
}

 public static void main(){
        Shape shape1 = ShapeFactory.getShape(ShapeFactory.SHAPE_CIRCLE);
        shape1.draw();

        Shape shape2 = ShapeFactory.getShape(ShapeFactory.SHAPE_SQUARE);
        shape2.draw();
    }

github代码地址

3.2.3 android源码中的工厂模式

com.android.camera.debug.Logger
com.android.camera.debug.Loggers
还有context.getSystemService("name")也可以看作是工厂模式。

3.3 抽象工厂模式(Abstract Factory Pattern)

3.3.1 模式描述

意图:提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。
适用性:以下情况使用抽象工厂模式:
1.一个系统要独立于它的产品的创建、组合和表示时。
2.一个系统要由多个产品系列中的一个来配置时。
3.当你要强调一系列相关的产品对象的设计以便进行联合使用时。
4.当你提供一个产品类库,而只想显示它们的接口而不是实现时。
结构图:

3.3.2 代码实现


//抽象产品
public interface AbstractProductA {
    void doSomething();
}

public interface AbstractProductB {
    void doSomething();
}


//产品的不同实现
public class ProductA1 implements AbstractProductA {
    @Override
    public void doSomething() {
        System.out.println("I'm ProductA1");
    }
}

public class ProductA2 implements AbstractProductA {
    @Override
    public void doSomething() {
        System.out.println("I'm ProductA2");
    }
}

public class ProductB1 implements AbstractProductB {
    @Override
    public void doSomething() {
        System.out.println("I'm ProductB1");
    }
}

public class ProductB2 implements AbstractProductB {
    @Override
    public void doSomething() {
        System.out.println("I'm ProductB2");
    }
}

//抽象工厂
public abstract class AbstractFactory {
    abstract AbstractProductA createProductA();
    abstract AbstractProductB createProductB();
}

//工厂的具体实现
public class ConcreteFactory1 extends AbstractFactory {
    @Override
    AbstractProductA createProductA() {
        return new ProductA1();
    }

    @Override
    AbstractProductB createProductB() {
        return new ProductB1();
    }
}

public class ConcreteFactory2 extends AbstractFactory {
    @Override
    AbstractProductA createProductA() {
        return new ProductA2();
    }

    @Override
    AbstractProductB createProductB() {
        return new ProductB2();
    }
}

//调用代码
public static void main() {
        AbstractFactory factory = new ConcreteFactory1();
        AbstractProductA pa = factory.createProductA();
        AbstractProductB pb = factory.createProductB();

        pa.doSomething();
        pb.doSomething();
    }

github代码地址
抽象工厂给我的感觉,就是把依赖倒置原则运用到了极致,完完全全的面向接口编程。

3.3.3 android源码中的抽象工厂模式

在Android中,抽象工厂比较少,可以把整个Service看作一个大抽象工厂,通过名字去拿服务,拿到服务对象后,再调用对象里的抽象方法。

3.4 建造者模式(Builder Pattern)

3.4.1 模式描述

意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
适用性:1.当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
2.当构造过程必须允许被构造的对象有不同的表示时。
结构图:

3.4.2 代码实现

public class Request {
    String url;
    String method;
    String body;

    private Request(String url, String method, String body) {
        this.url = url;
        this.method = method;
        this.body = body;
    }

    public String call() {
        return "this is data:" + url + method + body;
    }

    public static class Builder {
        String url;
        String method;
        String body;

        public Builder() {
            method = "get";
        }

        public Builder url(String url) {
            //在这里可以做其他处理处理
            this.url = url;
            return this;
        }

        public Builder method(String method) {
            //在这里可以做其他处理处理
            this.method = method;
            return this;
        }

        public Builder body(String body) {
            //在这里可以做其他处理处理
            this.body = body;
            return this;
        }

        public Request build() {
            return new Request(url, method, body);
        }
    }
}


        //调用代码
        Request.Builder builder = new Request.Builder();
        Request request = builder
                .url("url")
                .method("get")
                .body("body")
                .build();
        String data = request.call();
        System.out.println(data);

github代码地址

3.4.3 android源码中的建造者模式

android最常用到的建造者模式是dialog,使用代码如下:

        AlertDialog.Builder builder=new AlertDialog.Builder(null);
        builder
                .setView(null)
                .setTitle(1)
                .setIcon(2);
        AlertDialog dialog=builder.create();
        dialog.show();

此外,okhttp和retrofit等开源库也使用了建造者模式


        //okhttp
        MediaType JSON = MediaType.get("application/json; charset=utf-8");
        OkHttpClient client = new OkHttpClient();
        RequestBody body = RequestBody.create("json", JSON);
        Request request = new Request.Builder()
                .url("url")
                .post(body)
                .build();
        try {
            Response response = client.newCall(request).execute();
            String data = response.body().toString();
        } catch (IOException e) {
            e.printStackTrace();
        }


        //retrofit
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        GitHubService service = retrofit.create(GitHubService.class);

3.5 原型模式(Prototype Pattern)

3.5.1 模式描述

意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

适用性:
1.当一个系统应该独立于他的产品创建、构成和表示时。
2.当要实例化的类是运行时刻指定时,例如动态装载。
3.为了避免创建一个与产品类层次平行的工厂类层次时。
4.当一个类的实例只能有几个不同状态组合中的一种时。

结构图:

3.5.2 代码实现


public interface Prototype {
    public Prototype myClone();
}

public class ConcretePrototype implements Prototype {

    private String name;
    private boolean gender;

    public ConcretePrototype(String name, boolean gender) {
        this.name = name;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isGender() {
        return gender;
    }

    public void setGender(boolean gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "ConcretePrototype{" +
                "name='" + name + '\'' +
                ", gender=" + gender +
                '}';
    }

    @Override
    public Prototype myClone() {
        return new ConcretePrototype(name, gender);
    }
}

//调用代码
        Prototype p1 = new ConcretePrototype("name1", true);
        Prototype p2 = p1.myClone();
        System.out.println("p1==p2  =  " + (p1 == p2));

        if (p2 instanceof ConcretePrototype) {
            ConcretePrototype cp = ((ConcretePrototype) p2);
            cp.setName("new name");
            System.out.println(cp.toString());
        }

github代码地址

3.5.3 android源码中的原型模式

android中的Intent有用到原型模式,部分代码如下:

public class Intent implements Parcelable, Cloneable {

    @Override
    public Object clone() {
        return new Intent(this);
    }
	
	/**
     * Copy constructor.
     */
    public Intent(Intent o) {
        this(o, COPY_MODE_ALL);
    }
	
	 private Intent(Intent o, @CopyMode int copyMode) {
        this.mAction = o.mAction;
        this.mData = o.mData;
        this.mType = o.mType;
		......
	}
}

//调用代码
        Intent i1 = new Intent("action");
        Intent i2 = (Intent) i1.clone();

4.结构型模式

这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。

4.1 适配器模式(Adapter Pattern)

4.1.1 模式描述

意图:将一个类的接口装换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适用性:
1.当你想使用一个存在的类,而他的接口不符合你的需求。
2.你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
3.(仅适用于对象adapter)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配他的父类接口。
结构图:

4.1.2 代码实现


public interface Input5v1a {
    public void in();
}

public class Output220v {
    public void out() {
    }
}

public class PowerAdapter implements Input5v1a {
    final private Output220v output220v;

    public PowerAdapter(Output220v output220v) {
        this.output220v = output220v;
    }

    @Override
    public void in() {
        //把220v的输出电源转成5v1a的输入电源
        output220v.out();
        //return 5v1a
    }
}

//调用代码
        Output220v output220v = new Output220v();
        Input5v1a input5v1a = new PowerAdapter(output220v);
        input5v1a.in();

github代码地址

4.1.3 android源码中的适配器模式

最常见的是RecyclerView的Adapter,使用RecyclerView时,需要写一个Adapter继承自RecyclerView.Adapter并实现三个方法,RecyclerView再绑定这个实现的Adapter对象,然后就可以把数据转成view显示在界面上。简单示例代码如下

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyVH> {

    List<String> data;

    public MyAdapter(List<String> data) {
        this.data = data;
    }

    @NonNull
    @Override
    public MyVH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        TextView tv = new TextView(parent.getContext());
        return new MyVH(tv);
    }

    @Override
    public void onBindViewHolder(@NonNull MyVH holder, int position) {
        holder.textView.setText(data.get(position));
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    public static class MyVH extends RecyclerView.ViewHolder {
        TextView textView;

        public MyVH(@NonNull View itemView) {
            super(itemView);
            if (itemView instanceof TextView) {
                textView = (TextView) itemView;
            }
        }
    }
}


RecyclerView view = null;
        view.setAdapter(new MyAdapter(new ArrayList<>()));

4.2 桥接模式(Bridge Pattern)

4.2.1 模式描述

意图:将抽象部分与他的实现部分分离,使他们都可以独立地变化。
适用性:
1.当你不希望在抽象和它的实现之间有一个固定的绑定关系。例如是因为在程序运行时刻,实现部分可以被选择或者切换。
2.类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这时桥接模式使你可以对不同的抽象接口和实现部分进行组合,并分别对他们进行扩充。
3.对一个抽象的实现部分的修改,应对客户不产生影响,即客户的代码不必重新编译。
4.想在多个对象间共享实现,但同时要求客户并不知道这一点。
结构图:

4.2.2 代码实现


public interface Color {
    void draw(String box);
}

public class RedColor implements Color {
    @Override
    public void draw(String box) {
        System.out.println("red "+box);
    }
}

public abstract class Box {
    protected Color color;

    public Box(Color color) {
        this.color = color;
    }

    abstract void drawBox();
}


public class RedBox extends Box {
    public RedBox() {
        super(new RedColor());
    }

    @Override
    void drawBox() {
        this.color.draw("box");
    }
}

//调用代码
RedBox redBox = new RedBox();
        redBox.drawBox();

github代码地址

4.2.3 android源码中的桥接模式

AbsListView 与 ListAdapter 之间是桥接模式,类图如下

4.3 组合模式(Composite Pattern)

4.3.1 模式描述

意图:将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。

适用性:
1.你想表示对象的部分-整体层次结构。
2.你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

结构图:

4.3.2 代码实现

二叉树是最简单的组合模式


public class ListNode {
    public int value;

    public ListNode(int value) {
        this.value = value;
    }

    public ListNode left;
    public ListNode right;
}


//调用代码
 /*
         *   1
         *  / \
         * 2   3
         * */
        ListNode listNode = new ListNode(1);

        listNode.left = new ListNode(2);

        listNode.right = new ListNode(3);

github代码地址

4.3.3 android源码中的组合模式

ViewGroup和View就是典型的组合模式,ViewGroup是一个View,同时又包含了View。

public abstract class ViewGroup extends View{
    private View[] mChildren;
}

4.4 装饰器模式(Decorator Pattern)

4.4.1 模式描述

意图:动态地给已有对象添加功能。类对扩展开放,对修改关闭。

适用性:
1.在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
2.处理那些可以撤销的职责。
3.当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目爆炸增长。另一种情况可能是因为类定义被隐藏,或者类定义不能用于生成子类。

结构图:

4.4.2 代码实现


public abstract class Room {
    public abstract void fitment();//装修房间
}

public class NewRoom extends Room {
    @Override
    public void fitment() {
        System.out.println("这是新房子,装地板,装电");
    }
}

public abstract class RoomDecorator extends Room {
    protected  Room room;

    public RoomDecorator(Room room) {
        this.room = room;
    }

    @Override
    public void fitment() {
        room.fitment();
    }
}

public class Bedroom extends RoomDecorator {
    public Bedroom(Room room) {
        super(room);
    }

    @Override
    public void fitment() {
        super.fitment();
        System.out.println("装修成卧室,添加卧具");
    }
}


public class Kitchen extends RoomDecorator {
    public Kitchen(Room room) {
        super(room);
    }

    @Override
    public void fitment() {
        super.fitment();
        System.out.println("装修成厨房,添加厨房用品");
    }
}

//调用代码
 Room room1 = new NewRoom();
        Bedroom bedroom = new Bedroom(room1);
        bedroom.fitment();

        Room room2 = new NewRoom();
        Kitchen kitchen = new Kitchen(room2);
        kitchen.fitment();


github代码地址

4.4.3 android源码中的装饰器模式

Android中的Activity、Service、Application等都是一个Context,这里面实际上就是通过装饰者模式来实现的。下面以startActivity这个方法进行分析
Context是一个抽象类,定义了大量的抽象方法,包括startActivity;

public abstract class Context {
        public abstract void startActivity(@RequiresPermission Intent intent);
}

Context的实现类是ContextImpl,里面具体实现了startActivity方法;

class ContextImpl extends Context {
     @Override
    public void startActivity(Intent intent) {
        warnIfCallingFromSystemProcess();
        startActivity(intent, null);
    }

     @Override
    public void startActivity(Intent intent, Bundle options) {
        warnIfCallingFromSystemProcess();
        // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
        // generally not allowed, except if the caller specifies the task id the activity should
        // be launched in. A bug was existed between N and O-MR1 which allowed this to work. We
        // maintain this for backwards compatibility.
        final int targetSdkVersion = getApplicationInfo().targetSdkVersion;
        if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
                && (targetSdkVersion < Build.VERSION_CODES.N
                        || targetSdkVersion >= Build.VERSION_CODES.P)
                && (options == null
                        || ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity "
                            + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                            + " Is this really what you want?");
        }
        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }
}

通常在Activity、Service里面调用startActivity方法,实际上都是调用他们的父类ContextWrapper里面的startActivity方法。

    public class ContextWrapper extends Context {//Context包装类
        Context mBase;//持有Context引用

        public ContextWrapper(Context base) {//这里的base实际上就是ContextImpl
            mBase = base;
        }

        @Override
        public void startActivity(Intent intent) {
            mBase.startActivity(intent);//调用ContextImpl的startActivity()方法
        }

        //其他代码略
    }

startActivity的详细流程,会再写一篇专门的文章。

4.5 外观模式(Facade Pattern)

4.5.1 模式描述

意图:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这一接口使得子系统更加容易使用。

适用性:
1.当你要为一个复杂子系统提供一个简单接口时。
2.客户程序与抽象类的实现部分之间存在着很大的依赖性。引入外观模式将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
3.当你需要构建一个层次结构的子系统时,使用外观模式定义子系统中每层的入口点。

4.5.2 代码实现


public class SubSystem {

    public void turnOnTV() {
        System.out.println("turn on tv!");
    }

    public void setCD(String s) {
        System.out.println("set CD:" + s);
    }

    public void startWatching() {
        System.out.println("start watching!");
    }
}


public class Facade {
    SubSystem subSystem = new SubSystem();

    public void watchMovie(String s) {
        subSystem.turnOnTV();
        subSystem.setCD(s);
        subSystem.startWatching();
    }
}


//调用代码
        Facade facade = new Facade();
        facade.watchMovie("无间道.mp4");

github代码地址

4.5.3 android源码中的外观模式

外观模式是比较常见的设计模式,在android中的应用也比较广泛,比如Context类,里面封装了很多方法,比如startActivity,实际上是通过AMS来实现的,通过封装的方式,Context类隐藏了细节,我们只需要简单调用一个方法即可启动一个新的activity。

4.6 享元模式(Flyweight Pattern)

4.6.1 模式描述

意图:运用共享技术有效地支持大量细粒度的对象。

主要解决:在有大量对象时,有可能会造成内存溢出,可以把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有对象,避免重新创建。

结构图:

4.6.2 代码实现


public interface IBike {
    void billing(int time);
}

public class ShareBike implements IBike {

    final private int price;//单价

    public ShareBike(int price) {
        this.price = price;
    }

    @Override
    public void billing(int time) {
        int total = time * price;
        System.out.println("骑单车花费:" + total);
    }
}


public class BikeFactory {
    final private HashMap<String, IBike> pool = new HashMap<>();

    public IBike getBike(String name) {
        IBike bike;
        if (pool.containsKey(name)) {
            System.out.println("押金已交,直接用车:" + name);
            bike = pool.get(name);
        } else {
            System.out.println(name + "  第一次使用,交押金100元");
            bike = new ShareBike(2);
            pool.put(name, bike);
        }
        return bike;
    }
}

//调用代码
        BikeFactory factory = new BikeFactory();

        IBike bike1 = factory.getBike("ofo");
        bike1.billing(3);

        IBike bike2 = factory.getBike("mobai");
        bike2.billing(2);

        IBike bike3 = factory.getBike("ofo");
        bike3.billing(2);

github代码地址

4.6.3 android源码中的享元模式

在android中,通过Message.obtain();方法获取Message对象,这里就使用了享元模式。
还有java中的String,如果字符串常量池中有此字符,直接返回,否则先在字符串常量池中创建。

        String s1 = "abc";
        String s2 = "abc";
        System.out.println("s1==s2 : " + (s1 == s2));//true

        Message.obtain();

4.7 代理模式(Proxy Pattern)

4.7.1 模式描述

意图:为其他对象提供一种代理,以控制对这个对象的访问。生活中,代购,打官司等,都是一种代理模式。

适用性:在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用代理模式。常有以下四种代理:
1.远程代理(Remote Proxy),控制对远程对象(不同地址空间)的访问,它负责将请求及其参数进行编码,并向不同地址空间中的对象发送已经编码的请求;
2.虚拟代理(Virtual Proxy),根据需要创建开销很大的对象,它可以缓存实体的附加信息,以便延迟对它的访问,例如在网站加载一个很大的图片时,不能马上完成,可以用虚拟代理缓存图片的大小信息,然后生成一张临时图片代替原始图片;
3.保护代理(Protection Proxy),按权限控制对象的访问,它负责检查调用者是否具有实现一个请求所必须的访问权限;
4.智能代理(Smart Reference),取代了简单的指针,它在访问对象时执行一些附加操作,记录对象的引用次数,当第一次引用一个对象时,将它装入内存,在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。

结构图:

4.7.2 代码实现


public interface Image {
    void display();
}


public class RealImage implements Image {

    public String file;

    public RealImage(String file) {
        this.file = file;
        load();
    }

    private void load() {
        System.out.println("load file:" + file);
    }

    @Override
    public void display() {
        System.out.println("display image:" + file);
    }
}


public class ProxyImage implements Image {

    private RealImage realImage;
    final private String file;

    public ProxyImage(String file) {
        this.file = file;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(file);
        }
        realImage.display();
    }
}

//调用代码
        ProxyImage proxyImage = new ProxyImage("namei.jpg");
        proxyImage.display();

        proxyImage.display();

github代码地址

4.7.3 android源码中的代理模式

android中用到代理模式的地方比较多,比如ActivityManagerProxy这个代理类,他和ActivityManagerNative都实现了IActivityManager这个接口,IActivityManager是抽象主题,ActivityManagerProxy是代理类,真实主题是ActivityManagerNative,实际上ActivityManagerNative是个抽象类,真正的具体实现实在它的子类ActivityManagerService中。

此外还有AIDL也用到代理模式,当我们编写好AIDL文件后,编译器会自动给我们增加一些代码


public interface IRemoteService extends android.os.IInterface{
  public static abstract class Stub extends android.os.Binder implements ...{
    public static com.learnaidl.IRemoteService asInterface(..) {

        return new ..Proxy(obj);

      }

      private static class Proxy implements com.learnaidl.IRemoteService{
          ...
      }

  }  
}
//使用
IRemoteService.Stub()   

通过IRemoteService的Stub类拿对象,这个对象是通过一个代理类创建出来的。

4.7.4 静态代理和动态代理

从代码的角度来分,可以分为静态代理和动态代理。静态代理就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。动态代理类的源码是在程序运行期间根据反射等机制动态的生成,所以不存在代理类的字节码文件,代理类和委托类的关系是在程序运行时确定的。上例是静态代理。

动态代理需要实现InvocationHandler接口,然后重写invoke()方法,以下为动态代理实现代码:

public class DynamicProxy implements InvocationHandler {

    final private Object obj;

    public DynamicProxy(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态代理,调用方法之前");
        Object result = method.invoke(obj, args);//调用被代理的对象的方法
        System.out.println("动态代理,调用方法之后,result=" + result);
        return result;
    }
}

//调用代码
        //动态代理
        RealImage realImage = new RealImage("lufei.jpg");
        DynamicProxy dynamicProxy = new DynamicProxy(realImage);
        ClassLoader classLoader = realImage.getClass().getClassLoader();
        Image image = (Image) Proxy.newProxyInstance(classLoader,
                new Class[]{Image.class}, dynamicProxy);
        image.display();

更多静态代理和动态代理信息

5.行为型模式

这些设计模式特别关注对象之间的通信。

5.1 责任链模式(Chain of Responsibility Pattern)

5.1.1 模式描述

意图:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

适用性:
1.有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
2.你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
3.可处理一个请求的对象集合应被动态指定。

结构图:

5.1.2 代码实现


public class Request {
    enum RequestType {
        TYPE_1, TYPE_2
    }

    public RequestType type;
    public String name;

    public Request(RequestType type, String name) {
        this.type = type;
        this.name = name;
    }
}

public abstract class Handler {
    protected Handler successor;

    public Handler(Handler successor) {
        this.successor = successor;
    }

    protected abstract void handleRequest(Request request);
}


public class ConcreteHandler1 extends Handler {
    public ConcreteHandler1(Handler successor) {
        super(successor);
    }

    @Override
    protected void handleRequest(Request request) {
        if (request.type == Request.RequestType.TYPE_1) {
            System.out.println("ConcreteHandler1 handle  name=" + request.name);
            return;
        }
        if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

public class ConcreteHandler2 extends Handler {
    public ConcreteHandler2(Handler successor) {
        super(successor);
    }

    @Override
    protected void handleRequest(Request request) {
        if (request.type == Request.RequestType.TYPE_2) {
            System.out.println("ConcreteHandler2 handle  name=" + request.name);
            return;
        }
        if (successor != null) {
            successor.handleRequest(request);
        }
    }
}


//调用代码
        Handler handler1 = new ConcreteHandler1(null);
        Handler handler2 = new ConcreteHandler2(handler1);

        handler2.handleRequest(new Request(Request.RequestType.TYPE_1, "request 111"));
        handler2.handleRequest(new Request(Request.RequestType.TYPE_2, "request 22"));

github代码地址

5.1.3 android源码中的责任链模式

android中事件分发机制,父view接到事件,传递给子view,就是责任链模式。
还有okhttp中,对请求的处理也是用到了责任链模式。

5.2 命令模式(Command Pattern)

5.2.1 模式描述

意图:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

适用性:
1.抽象出待执行的动作以参数化某对象;
2.在不同的时刻指定、排列和执行请求;
3.支持取消操作;
4.支持修改日志;
5.用构建在原语操作上的高层操作构造一个系统。

结构图:

5.2.2 代码实现


public interface Order {
    void execute();
}

public class Stock {

    public String name;
    public int quantity;

    public Stock(String name, int quantity) {
        this.name = name;
        this.quantity = quantity;
    }

    public void buy() {
        System.out.println("Stock [ Name: " + name + "," +
                " Quantity: " + quantity + " ] bought");
    }

    public void sell() {
        System.out.println("Stock [ Name: " + name + ", " +
                "Quantity: " + quantity + " ] sold");
    }
}


public class BuyStock implements Order {

    private Stock stock;

    public BuyStock(Stock stock) {
        this.stock = stock;
    }

    @Override
    public void execute() {
        stock.buy();
    }
}

public class SellStock implements Order {

    private Stock stock;

    public SellStock(Stock stock) {
        this.stock = stock;
    }

    @Override
    public void execute() {
        stock.sell();
    }
}

public class Broker {
    private List<Order> orderList=new ArrayList<>();

    public void takeOrder(Order order){
        orderList.add(order);
    }

    public void placeOrders(){
        for(Order order:orderList){
            order.execute();
        }
        orderList.clear();
    }
}

//调用代码
        Stock stock = new Stock("huawei", 100);

        BuyStock buyStock = new BuyStock(stock);
        SellStock sellStock = new SellStock(stock);

        Broker broker = new Broker();
        broker.takeOrder(buyStock);
        broker.takeOrder(sellStock);

        broker.placeOrders();

github代码地址

5.2.3 android源码中的命令模式

Thread的使用就是一个简单的命令模式

new Thread(new Runnable(){
    @Override
    public void run(){
        //do something
    }
}).start();

Thread的start()方法即命令的调用者,同时Thread的内部会调用Runnable的run(),这里Thread又充当了具体的命令角色,最后的Runnable则是接受者,负责最后的功能处理。

另外,Handler也是典型的命令模式。Handler接受者,执行消息的处理操作;Looper调用者,调用消息的处理方法;Message命令角色,消息类。

5.3 解释器模式(Interpreter Pattern)

5.3.1 模式描述

意图:给定一个语言,定义他的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。这种模式被用在SQL解析、符号处理引擎等。

适用性:当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。

结构图:

5.3.2 代码实现


public interface Expression {
   public boolean interpret(String context);
}

public class TerminalExpression implements Expression {

    String data;

    public TerminalExpression(String data) {
        this.data = data;
    }

    @Override
    public boolean interpret(String context) {
        return context.contains(data);
    }
}

public class OrExpression implements Expression {

    Expression expression1;
    Expression expression2;

    public OrExpression(Expression expression1, Expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }

    @Override
    public boolean interpret(String context) {
        return expression1.interpret(context) || expression2.interpret(context);
    }
}

public class AndExpression implements Expression {
    Expression expression1;
    Expression expression2;

    public AndExpression(Expression expression1, Expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }

    @Override
    public boolean interpret(String context) {
        return expression1.interpret(context) && expression2.interpret(context);
    }
}


//调用代码
    //规则:Robert 和 John 是男性
    public static Expression getMaleExpression() {
        Expression robert = new TerminalExpression("Robert");
        Expression john = new TerminalExpression("John");
        return new OrExpression(robert, john);
    }

    //规则:Julie 是一个已婚的女性
    public static Expression getMarriedWomenExpression() {
        Expression julie = new TerminalExpression("Julie");
        Expression married = new TerminalExpression("Married");
        return new AndExpression(julie, married);
    }

    public static void main() {

        System.out.println("John is male:" + getMaleExpression().interpret("John"));
        System.out.println("Amy is male:" + getMaleExpression().interpret("Amy"));
        System.out.println("Amy is Married women:" + getMarriedWomenExpression().interpret("Amy"));
        System.out.println("Julie is Married women:" + getMarriedWomenExpression().interpret("Married Julie"));

    }


github代码地址

5.3.3 android源码中的解释器模式

android中的AndroidManifest.xml文件,实际上是由PackageManagerService使用android.content.pm.PackageParser这个类来解释的,对于AndroidManifest中的每一个标签,都有对应的类去保存相应的信息。

5.4 迭代器模式(Iterator Pattern)

5.4.1 模式描述

意图:提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。

适用性:
1.访问一个聚合对象的内容,而无需暴露它的内部表示。
2.支持对聚合对象的多种遍历。
3.为遍历不同的聚合结构提供一个统一的接口,即支持多态迭代。

结构图:

5.4.2 代码实现


public interface Iterator {
    boolean hasNext();//是否存在下一条记录

    Object next();//返回当前记录,并移到下一条记录
}

public interface Aggregate {
    int size();//容器大小

    String get(int location);//获取指定位置的数据

    void add(String s);//添加数据到容器

    void remove(String s);//从容器中移除数据

    Iterator iterator();//返回容器的迭代器
}

public class DeliveryIterator implements Iterator {

    private Aggregate aggregate;//容器对象
    private int index;//当前索引

    public DeliveryIterator(Aggregate aggregate) {
        this.aggregate = aggregate;
        this.index = 0;
    }

    @Override
    public boolean hasNext() {
        return index < aggregate.size();
    }

    @Override
    public Object next() {
        return aggregate.get(index++);
    }
}


public class DeliveryAggregate implements Aggregate {

    private List<String> list = new ArrayList<>();//内部使用list存储数据

    @Override
    public int size() {
        return list.size();
    }

    @Override
    public String get(int location) {
        return list.get(location);
    }

    @Override
    public void add(String s) {
        list.add(s);
    }

    @Override
    public void remove(String s) {
        list.remove(s);
    }

    @Override
    public Iterator iterator() {
        return new DeliveryIterator(this);
    }
}

//调用代码
        Aggregate aggregate = new DeliveryAggregate();
        aggregate.add("1111111");
        aggregate.add("22222");
        aggregate.add("3333333");
        aggregate.add("44");

        Iterator iterator = aggregate.iterator();
        while (iterator.hasNext()) {
            System.out.println("当前数据为:" + iterator.next());
        }
        System.out.println("没有更多数据了。。。");

github代码地址

5.4.3 android源码中的迭代器模式

java中的Map、List等都使用了迭代器模式。android中使用数据库查询时返回的Cursor油标对象,实际上就是使用了迭代器模式实现的。


//Cursor使用
        Cursor cursor = null;
        if (cursor.moveToFirst()) {
            do {
                cursor.getInt(0);//获取第一列数据
                cursor.getString(1);//获取第二列数据
            } while (cursor.moveToFirst());//移到下一行
        }

//Cursor源码
//Cursor是一个接口,实际上就是迭代器接口
public interface Cursor extends Closeable {
    //其他代码略
    boolean moveToFirst();
    int getInt(int columnIndex);
    String getString(int columnIndex);
    boolean moveToNext();
}

5.5 中介者模式(Mediator Pattern)

5.5.1 模式描述

意图:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地互相引用,从而使耦合松散,而且可以独立地改变他们之间的交互。

适用性:
1.一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
2.一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
3.想定制一个分布在多个类中的行为,而又不想生成太多的子类。

结构图:

5.5.2 代码实现


public interface HouseMediator {
    void notice(Person person, String msg);
}

public abstract class Person {

    String name;
    HouseMediator houseMediator;

    public Person(String name, HouseMediator houseMediator) {
        this.name = name;
        this.houseMediator = houseMediator;
    }

    public abstract void send(String msg);//发布消息

    public abstract void getNotice(String msg);//接收消息
}


public class Landlord extends Person {
    
    public Landlord(String name, HouseMediator houseMediator) {
        super(name, houseMediator);
    }

    @Override
    public void send(String msg) {
        System.out.println(name + "房东发布消息:" + msg);
        houseMediator.notice(this, msg);
    }

    @Override
    public void getNotice(String msg) {
        System.out.println(name + "房东收到消息:" + msg);
    }
}


public class Purchaser extends Person {

    public Purchaser(String name, HouseMediator houseMediator) {
        super(name, houseMediator);
    }

    @Override
    public void send(String msg) {
        System.out.println(name + "买房者发布消息:" + msg);
        houseMediator.notice(this, msg);
    }

    @Override
    public void getNotice(String msg) {
        System.out.println(name + "买房者收到消息:" + msg);
    }
}

public class LiangJia implements HouseMediator {

    List<Landlord> landlordList = new ArrayList<>();
    List<Purchaser> purchaserList = new ArrayList<>();

    public void addLandlord(Landlord landlord) {
        landlordList.add(landlord);
    }

    public void addPurchaser(Purchaser purchaser) {
        purchaserList.add(purchaser);
    }

    @Override
    public void notice(Person person, String msg) {
        System.out.println("中介者收到消息,并转发给目标人群");
        if (person instanceof Landlord) {
            for (Purchaser p : purchaserList) {
                p.getNotice(msg);
            }
        } else if (person instanceof Purchaser) {
            for (Landlord l : landlordList) {
                l.getNotice(msg);
            }
        }
    }
}

//调用代码
        LiangJia liangJia = new LiangJia();
        Landlord bob = new Landlord("Bob", liangJia);
        liangJia.addLandlord(bob);
        liangJia.addLandlord(new Landlord("Amy", liangJia));
        liangJia.addPurchaser(new Purchaser("Jerry", liangJia));
        Purchaser jack = new Purchaser("Jack", liangJia);
        liangJia.addPurchaser(jack);

        bob.send("深圳湾壹号,别墅出租");

        jack.send("求租一个单间");

github代码地址

5.5.3 android源码中的中介者模式

android中锁屏功能,通过类com.android.systemui.keyguard.KeyguardViewMediator来协调处理,KeyguardViewMediator就是一个中介者的角色。

5.6 备忘录模式(Memento Pattern)

5.6.1 模式描述

意图:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。

适用性:
1.必须保存一个对象在某一时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
2.如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。

结构图:

5.6.2 代码实现


public class Memento {
    public int coin;//金币
    public int level;//等级
}

public class Game {
    private int coin = 0;
    private int level = 1;

    @Override
    public String toString() {
        return "Game{" +
                "coin=" + coin +
                ", level=" + level +
                '}';
    }

    public void play() {
        System.out.println("打野。。。");
        level++;
        System.out.println("等级提升了,当前等级=" + level);
        coin += 22;
        System.out.println("获得金币22,当前金币=" + coin);
    }

    public void exit() {
        System.out.println("退出游戏,游戏属性=" + toString());
    }

    public Memento createMemento() {
        Memento memento = new Memento();
        memento.coin = coin;
        memento.level = level;
        return memento;
    }

    public void setMemento(Memento memento) {
        level = memento.level;
        coin = memento.coin;
        System.out.println("读取存档信息:" + toString());
    }
}


public class Caretaker {
    private Memento memento;

    public void setMemento(Memento memento) {
        this.memento = memento;
    }

    public Memento getMemento() {
        return memento;
    }
}

//调用代码
        System.out.println("第一次进入游戏");
        Game game = new Game();
        game.play();
        Memento memento = game.createMemento();
        Caretaker caretaker = new Caretaker();
        caretaker.setMemento(memento);
        game.exit();

        System.out.println("_________---------________");
        System.out.println("第二次进入游戏");
        Game game2 = new Game();
        System.out.println("游戏属性:" + game2.toString());
        game2.setMemento(caretaker.getMemento());
        System.out.println("游戏属性:" + game2.toString());
        game2.play();
        System.out.println("游戏属性:" + game2.toString());
        game2.exit();

github代码地址

5.6.3 android源码中的备忘录模式

Activity提供了状态保存机制,来保证Activity在被系统回收后能够恢复当前Activity的数据。用onSaveInstanceState来保存当前Activity的状态,用onRestoreInstanceState来恢复Activity状态。以下是两个方法的源码:

    protected void onSaveInstanceState(Bundle outState) {//保存各种状态

        //1.保存Activity对应Window的状态信息
        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());

        //2.如果存在Fragments,则保存所有Fragments的状态信息
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }

        //3.如果设置了ActivityLifecycleCallbacks回调,那么会调用ActivityLifecycleCallbacks的onSaveInstanceState来进行保存状态信息
        getApplication().dispatchActivitySaveInstanceState(this, outState);
    }

       protected void onRestoreInstanceState(Bundle savedInstanceState) {
        if (mWindow != null) {
            //获取保存过的window状态信息
            Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
            //如果存在状态信息,则window进行恢复
            if (windowState != null) {
                mWindow.restoreHierarchyState(windowState);
            }
        }
    }

5.7 观察者模式(Observer Pattern)

5.7.1 模式描述

意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。

适用性:
1.当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将二者封装在独立的对象中以使他们可以各自独立地改变和复用。
2.当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。
3.当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,你不希望这些对象是紧密耦合的。

结构图:

5.7.2 代码实现


public abstract class Observer {
    protected Subject subject;
    public abstract void update();
}

public class Subject {
    final private List<Observer> observers = new ArrayList<>();
    private int state;

    public int getState() {
        return state;
    }

    public void setState(int i) {
        state = i;
        notifyAllObserver();
    }

    public void attach(Observer observer) {
        observers.add(observer);
    }

    public void notifyAllObserver() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}


public class BinaryObserver extends Observer {

    public BinaryObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println("Binary String:" + Integer.toBinaryString(subject.getState()));
    }
}

public class HexObserver extends Observer {
    public HexObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println("Hex String:" + Integer.toHexString(subject.getState()));
    }
}

public class OctalObserver extends Observer {
    public OctalObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println("Octal String:" + Integer.toOctalString(subject.getState()));
    }
}

//调用代码
        Subject subject = new Subject();

        new HexObserver(subject);
        new OctalObserver(subject);
        new BinaryObserver(subject);

        subject.setState(14);
        subject.setState(23);

github代码地址

5.7.3 android源码中的观察者模式

RecyclerView.Adapter的notifyDataSetChanged()使用的观察者模式,代码如下


public final void notifyDataSetChanged() {
            mObservable.notifyChanged();
        }

 public void notifyChanged() {
            // since onChanged() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }

5.8 状态模式(State Pattern)

5.8.1 模式描述

意图:允许一个对象在其内部状态改变时改变他的行为。对象看起来似乎修改了它的类。

适用性:
1.一个对象的行为取决于他的状态,并且他必须在运行时刻根据状态改变他的行为。
2.一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。

结构图:

5.8.2 代码实现


public class Context {
    public State state;
}

public interface State {
    public void doAction(Context context);
}

public class StartState implements State {
    @Override
    public void doAction(Context context) {
        System.out.println("player is in start state");
        context.state = this;
    }

    @NonNull
    @Override
    public String toString() {
        return "Start State";
    }
}

public class StopState implements State {
    @Override
    public void doAction(Context context) {
        System.out.println("Player is in stop state");
        context.state = this;
    }

    @NonNull
    @Override
    public String toString() {
        return "Stop State";
    }
}

//调用代码
        Context context = new Context();

        StartState startState = new StartState();
        startState.doAction(context);
        System.out.println("" + context.state.toString());

        StopState stopState = new StopState();
        stopState.doAction(context);
        System.out.println("" + context.state.toString());

github代码地址

5.8.3 android源码中的状态模式

android中播放器依赖自身状态,进行播放暂停操作。

5.9 策略模式(Strategy Pattern)

5.9.1 模式描述

意图:定义一系列的算法,把他们一个个封装起来,并且使他们可以互相替换。本模式使得算法可以独立于使用他的客户而改变。

适用性:
1.许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
2.需要使用一个算法的不同变体。例如,你可能会定义一些放映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时,可以使用策略模式。
3.算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
4.一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入他们各自的Strategy类中,以代替这些条件语句。

结构图:

5.9.2 代码实现


public interface Strategy {
    public int doOperation(int n1, int n2);
}

public class Add implements Strategy {
    @Override
    public int doOperation(int n1, int n2) {
        return n1 + n2;
    }
}

public class Subtract implements Strategy {
    @Override
    public int doOperation(int n1, int n2) {
        return n1 - n2;
    }
}

public class Multiply implements Strategy {
    @Override
    public int doOperation(int n1, int n2) {
        return n1 * n2;
    }
}

public class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public int execute(int n1, int n2) {
        return strategy.doOperation(n1, n2);
    }
}

//调用代码
        Context context1 = new Context(new Add());
        System.out.println("10+6=" + context1.execute(10, 6));

        Context context2 = new Context(new Subtract());
        System.out.println("10-6=" + context2.execute(10, 6));

        Context context3 = new Context(new Multiply());
        System.out.println("10*6=" + context3.execute(10, 6));

github代码地址

5.9.3 android源码中的策略模式

android中,通过设置不同的adapter(即不同的策略),可以显示不同的recyclerView布局。
另外,动画中的差值器(Interpolator)也用到了策略模式。

5.10 模板方法模式(Template Pattern)

5.10.1 模式描述

意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构,即可重定义该算法的某些特定步骤。

适用性:
1.一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
2.个子类中公共的行为应被提取出来,并集中到一个公共父类中,以避免代码重复。
3.控制子类扩展。

结构图:

5.10.2 代码实现


public class BaseActivity extends Activity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //do something
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //do something
    }
}

public class HomeActivity extends BaseActivity {
}

github代码地址

5.10.3 android源码中的模板方法模式

如上例代码,模板方法模式在日常开发中用得比较频繁。