Java和Kotlin设计模式


单例模式


单例模式:保证整个程序只有一个实例。

套路:1、构造函数私有,防止在外部new对象;2、内部必须提供一个静态的方法,让外部调用。


饿汉模式


java实现:

public class SingletonEHan {

    private SingletonEHan() {
    }
    
    private static SingletonEHan singletonEHan = new SingletonEHan();
    
    public static SingletonEHan getInstance() {
        return singletonEHan;
    }
//  SingletonEHan instance= SingletonEHan.getInstance();
}

kotlin实现:

object SingletonEHan {
}
  • 优点:比较简单,在类加载的时候就完成了实例化,避免了线程的同步问题。
  • 缺点:由于在类加载的时候就实例化了,也就是说可能我没有用到这个实例,但是它也会加载,会造成内存的浪费(但是这个浪费可以忽略)。

懒汉模式,四种方式


java实现:

public class SingletonLanHan {

    private SingletonLanHan() {
    }
    
    /**
     * 单例模式的懒汉式[线程不安全,不可用]
     */
    private static SingletonLanHan singletonLanHan;
    public static SingletonLanHan getInstance() {
        if (singletonLanHan == null) { //多线程并发,这里线程是不安全的,可能得到两个不同的实例
            singletonLanHan = new SingletonLanHan();
        }
        return singletonLanHan;
    }

    /**
     * 懒汉式线程安全的:加锁,[线程安全,效率低不推荐使用]
     * 缺点:效率太低,每个线程在想获得类的实例时候,执行getSingletonLanHanTwo()方法都要进行同步。
     */
    private static SingletonLanHan singletonLanHanTwo;
    public static synchronized SingletonLanHan getSingletonLanHanTwo() {
        if (singletonLanHanTwo == null) {
            singletonLanHanTwo = new SingletonLanHan();
        }
        return singletonLanHanTwo;
    }

    /**
     * 单例模式懒汉式[线程不安全,不可用]
     * 虽然加了锁,new Singleton()跳出这个锁时,另一个已经进入if语句的线程同样会实例化另外一个Singleton对象。
     * 
     */
    private static SingletonLanHan singletonLanHanThree = null;
    public static SingletonLanHan getSingletonLanHanThree() {
        if (singletonLanHanThree == null) {
            synchronized (SingletonLanHan.class) {// 线程不安全
                singletonLanHanThree = new SingletonLanHan();
            }
        }
        return singletonLanHanThree;
    }

    /**
     * 懒汉式双重校验
     * 缺点:不推荐用,下面解释
     */
    private static SingletonLanHan singletonLanHanFour;
    public static SingletonLanHan getSingletonLanHanFour() {
        if (singletonLanHanFour == null) {//只执行一次锁,所以效率高一些
            synchronized (SingletonLanHan.class) {
                if (singletonLanHanFour == null) {
                    singletonLanHanFour = new SingletonLanHan();
                }
            }
        }
        return singletonLanHanFour;
    }
}

kotlin实现:

class SingletonDemo private constructor() {
    companion object {
        private var instance: SingletonDemo? = null
            get() {
                if (field == null) {
                    field = SingletonDemo()
                }
                return field
            }

        @Synchronized//线程安全的懒汉式
        fun get(): SingletonDemo{
        //细心的小伙伴肯定发现了,这里不用getInstance作为为方法名,是因为在伴生对象声明时,内部已有getInstance方法,所以只能取其他名字
         return instance!!
        }
    }
}

1、开辟一块内存空间,2、初始化对象,3、给变量赋值,指向内存地址。在java中2和3的顺序不一定,也可能先3再2。用volatile保证123的顺序执行,防止重排序。


volatile[同步锁DCL]


Java实现:

public class SingletonLanHan {

    private SingletonLanHan() {
    }
    
    //volatile解决了gvm指令重排序优化
    private static volatile SingletonLanHan singletonLanHanFour;

    public static SingletonLanHan getSingletonLanHanFour() {
        if (singletonLanHanFour == null) {
            synchronized (SingletonLanHan.class) {
                if (singletonLanHanFour == null) {
                    singletonLanHanFour = new SingletonLanHan();
                }
            }
        }
        return singletonLanHanFour;
    }
}

kotlin实现:

class SingletonDemo private constructor() {
    companion object {
        val instance: SingletonDemo by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
        SingletonDemo() }
    }
}

volatile关键字作用:防止重排序,线程可见性。

线程可见性:某一个线程改了公用对象(变量),短时间内另一个线程可能是不可见的,因为每一个线程都有自己的缓存区(线程工作区)。

举例:可以看加不加volatile的区别:

public class VolatileTest {
    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();
        new Thread(td).start();
        while(true){
            if(td.isFlag()){
                System.out.println("主线程flag:" + td.isFlag());
                break;
            }
        }
    }
}
class ThreadDemo implements Runnable {
    private volatile boolean flag = false;
    @Override
    public void run() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
        }
        flag = true;
        System.out.println("其他线程flag=" + isFlag());
    }
    public boolean isFlag() {
        return flag;
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

静态内部类


Java实现:

/**
 * 内部类[推荐用]
 * 在饿汉式方式是只要Singleton类被装载就会实例化,
 * 内部类是在需要实例化时,调用getInstance方法,才会装载SingletonHolder类
 * 优点:避免了线程不安全,延迟加载,效率高。
 */
public class SingletonIn {

    private SingletonIn() {
    }

    private static class SingletonInHodler {
        private static final SingletonIn singletonIn = new SingletonIn();
    }

    public static SingletonIn getSingletonIn() {
        return SingletonInHodler.singletonIn;
    }
}

kotlin实现:

class SingletonDemo private constructor() {
    companion object {
        val instance = SingletonHolder.holder
    }
    private object SingletonHolder {
        val holder= SingletonDemo()
    }
}

枚举


/**
 * 枚举[推荐使用]
 * SingletonEnum.instance
 * 这里的instance即为SingletonEnum类型的引用所以得到它就可以调用枚举中的方法了。
 * 借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
 */

public enum SingletonEnum {

    instance;

    private SingletonEnum() {
    }
    public void whateverMethod() {
    }
    // SingletonEnum.instance.method();
}

容器管理


SystemServiceRegistry.getSystemService系统的服务就是用的这种

public class Singleton {
    private static Map<String,Object> mSingleMap = new HashMap<>();

    static {
        mSingleMap.put("activity_manager",new Singleton());
    }

    private Singleton() {

    }

    public static Object getService(String serviceName){
        return mSingleMap.get(serviceName);
    }
}

补充复习static


static关键字的特点:随着类的加载而加载,随着类的消失而消失;优先于对象存在;被类的所有对象共享。

静态变量存储于方法区的静态区;成员变量存储于堆内存。

静态代码块:在类中方法外出现,并加上static修饰;用于给类进行初始化(全局初始化),在类加载的时候就执行,并且只执行一次。main主方法所在的类中的静态代码块优先于主方法执行。

class Student {
    static {
        System.out.println("Student 静态代码块");
    }
    
    {
        System.out.println("Student 构造代码块");
    }
    
    public Student() {
        System.out.println("Student 构造方法");
    }
}
class Demo2_Student {
    static {
        System.out.println("Demo2_Student静态代码块");
    }
    
    public static void main(String[] args) {
        System.out.println("我是main方法");
        
        Student s1 = new Student();
        Student s2 = new Student();
    }
}

输出结果:

Demo2_Student静态代码块
我是main方法
Student 静态代码块
Student 构造代码块
Student 构造方法
Student 构造代码块
Student 构造方法

工厂模式

简单工厂模式


简单工厂模式:提供专门的工厂类用于创建对象,将对象的创建和对象的使用分离开。客户端只知道传入工厂类的参数,不需要关心具体的实现。它不属于GoF23种设计模式,但在软件开发中应用也较为频繁。

实例

Bitmap bitmap = BitmapFatory.deresources(res,id);

简单工厂场景


使用简单工厂模式设计一个可以创建圆形、方形和三角形的绘图工具。

//抽象类 
public interface IPain {
    void draw();
}

//具体产品类
class Triangle implements IPain {
    @Override
    public void draw() {
        System.out.println("画出三角形");
    }
}

class Square implements IPain {
    @Override
    public void draw() {
        System.out.println("画出正方形");
    }
}

class Circle implements IPain {
    @Override
    public void draw() {
        System.out.println("画出圆形");
    }
}
//工厂类
public class PainFactory {
    //静态工厂方法
    public static IPain create(int type){
        switch (type) {
        case 1:
            return new Triangle();
        case 2:
            return new Square();
        case 3:
            return new Circle();
        default:
            return new Circle();
        }
    }
}
//客户端
public class Client {
    public static void main(String[] args) {
        //通过静态工厂方法创建产品 
        IPain mPain = PainFactory.create(2);
        mPain.draw();
    }
}

在简单工厂模式包含如下几个角色:


  1. 工厂类,负责实现创建所有产品实例,在工厂类中提供了静态方法,可以被外界直接调用,返回抽象产品类Product。

  2. Product抽象产品角色,它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,所有创建的具体产品对象都是其子类对象。

  3. 具体产品角色,都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。

在简单工厂模式中,客户端通过工厂类来创建一个产品类的实例,而无须直接使用new关键字来创建对象。


工厂方法模式


简单工厂Factory Method Pattern,模式最大的缺点是当有新产品要加入到系统中时,必须修改工厂类。

工厂方法模式中,不再提供一个统一的工厂类,而是针对不同的产品提供不同的工厂。提供一个抽象工厂接口来声明抽象工厂方法,其子类来具体实现工厂方法,创建具体的产品对象。即把对象的实现延迟到子类完成。

实例:

//List:Factory抽象工厂,ArrayList:具体的工厂Factory
//Iterator:抽象产品Product,ArrayListIterator:具体的产品
List<String> list = new ArrayList<String>();
list.iterator();

工厂方法场景


玩具工厂生产动物玩具,发出不同叫声。

//抽象产品-玩具
interface IToy {
    void makeNoise(String string);
}

//具体产品
class DogToy implements IToy {
    public void makeNoise(String string) {
        System.out.println(string + "汪汪汪的叫。" );
    }
}

//具体产品
class CatToy implements IToy {
    public void makeNoise(String string) {
        System.out.println(string + "喵喵喵的叫。");
    }
}

//抽象工厂
abstract class IToyFactory {
    abstract IToy createToy();
}

//具体工厂
class DogFactory extends IToyFactory {
    public IToy createToy() {
        return new DogToy();
    }
}

//具体工厂
class CatFactory extends IToyFactory {
    public IToy createToy() {
        return new CatToy();
    }
}

//客户端
class Client {
    public static void main(String args[]) {
        IToyFactory factory = new CatFactory();
        IToy toy = factory.createToy();
        toy.makeNoise("我是cat。");
        //factory.createToy().makeNoise("我是cat。");
    }
}

工厂方法模式的几个角色:


  1. Product抽象产品角色和具体产品角色,和简单工厂模式类似,不再累述。

  2. Factory(抽象工厂):是工厂方法模式的核心,在抽象工厂类中,声明了抽象工厂方法,用于返回一个产品。可以是接口,也可以是抽象类或者具体类。

  3. ConcreteFactory(具体工厂):它是抽象工厂类的子类,实现了抽象工厂中的工厂方法,并可由客户端调用,返回一个具体产品类的实例

在实际使用时,具体工厂类在实现工厂方法时除了创建具体产品对象之外,还可以负责产品对象的初始化工作以及一些资源和环境配置工作,例如连接数据库、创建文件等。


抽象工厂模式


抽象工厂模式Abstract Factory Pattern

待更新


建造者模式

介绍


建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。

建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品。

简单来说,复杂对象是指那些包含多个成员属性的对象,这些成员属性也称为部件或零件,如汽车包括方向盘、发动机、轮胎等部件,电子邮件包括发件人、收件人、主题、内容、附件等部件。


角色


在建造者模式中包含如下几个角色:

  1. Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。

  2. ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。

  3. Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。

  4. Director(指挥者):负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。

客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。

建造者模式与抽象工厂模式有点相似,但是建造者模式返回一个完整的复杂产品,而抽象工厂模式返回一系列相关的产品。


场景


实例:生产机器人,包含机器人服装,脸型,机器人功能

//产品,包含很多组件
class RobotProduct {
    private String type; //机器人功能
    private String face; //脸型
    private String costume; //服装

    public void setType(String type) {
        this.type = type;
    }
    public void setFace(String face) {
        this.face = face;
    }
    public void setCostume(String costume) {
        this.costume = costume;
    }

    public String getType() {
        return (this.type);
    }
    public String getFace() {
        return (this.face);
    }
    public String getCostume() {
        return (this.costume);
    }
}

//抽象建造者
abstract class RobotBuilder {

    protected RobotProduct robot = new RobotProduct();

    public abstract void buildType();
    public abstract void buildFace();
    public abstract void buildCostume();

    //工厂方法,返回一个完整机器人
    public RobotProduct createRobot() {
        return robot;
    }
}

//具体建造者
class ManBuilder extends RobotBuilder {

    public void buildType() {
        robot.setType("男仆");
    }

    public void buildFace() {
        robot.setFace("英俊");
    }

    public void buildCostume() {
        robot.setCostume("西服");
    }
}

//具体建造者
class WomanBuilder extends RobotBuilder {
    public void buildType() {
        robot.setType("女仆");
    }

    public void buildFace() {
        robot.setFace("漂亮");
    }

    public void buildCostume() {
        robot.setCostume("短裙");
    }
}

//指挥者类定义了construct()方法,该方法拥有一个抽象建造者类型的参数,在该方法内部实现了机器人的逐步构建
class RobotController {
    //逐步构建复杂产品对象
    public RobotProduct construct(RobotBuilder ab) {
        RobotProduct robot;
        ab.buildType();
        ab.buildFace();
        ab.buildCostume();
        robot = ab.createRobot();
        return robot;
    }
}

class Client {
    public static void main(String args[]) {
        RobotBuilder ab =  new WomanBuilder();
        RobotController ac = new  RobotController();

        RobotProduct robot = ac.construct(ab); //通过指挥者创建完整的建造者对象

        System.out.println(robot.getType()  + "的外观:");
        System.out.println("面容:" + robot.getFace());
        System.out.println("服装:" + robot.getCostume());
    }
}

变形


建造者模式的变形,也是在源码和开源项目中长用的,比如:AlertDialog

//产品,包含很多组件
class RobotProduct {
    private String type; //机器人功能
    private String face; //脸型
    private String costume; //服装
    public void apply(RobotBuilder.RobotParmas parmas) {
        type = parmas.type;
        face = parmas.face;
        costume = parmas.costume;
    }
    @Override
    public String toString() {
        return type + "的外观:" + "面容:" + face + "服装:" + costume;
    }
}

//具体建造者
class RobotBuilder {

    private RobotBuilder.RobotParmas parmas;

    public RobotBuilder() {
        this.parmas = new RobotBuilder.RobotParmas();
    }
    public RobotBuilder makeType(String type) {
        parmas.type = type;
        return this;
    }
    public RobotBuilder makeFace(String face) {
        parmas.face = face;
        return this;
    }
    public RobotBuilder makeCostume(String costume) {
        parmas.costume = costume;
        return this;
    }
    //真正构建
    public RobotProduct build() {
        RobotProduct produc = new RobotProduct();
        produc.apply(parmas);
        return produc;
    }

    class RobotParmas {
        public String type; //机器人功能
        public String face; //脸型
        public String costume; //服装
    }
}

class Client {
    public static void main(String args[]) {
         RobotProduct product = new RobotBuilder().makeType("女仆").makeFace("俊俏").makeCostume("护士装").build();
         System.out.println(product.toString());
    }
}

Java和Kotlin


Java:

public class PenJava {

    private Builder builder;

    public PenJava(Builder builder) {
        this.builder = builder;
    }

    public void write(){
        System.out.println("color:" + builder.color + ",width" + builder.width + ",round" + builder.round);
    }

    public static class Builder{
        private String color = "white";
        private Float width = 1.0f;
        private Boolean round = false;

        public Builder color(String color){
            this.color = color;
            return this;
        }

        public Builder width(Float width){
            this.width = width;
            return this;
        }

        public Builder round(Boolean round){
            this.round = round;
            return this;
        }

        public PenJava build(){
            return new PenJava(this);
        }
    }
}

Kotlin:

class Pen {
    var color = "white"
    var width = 1.0f
    var round = false

    fun write() {
        println("color:${color},width:${width},round:${round}")
    }
}

fun main(){
    val panjava = PenJava.Builder().color("yellow").width(3f).round(true).build()
    panjava.write()

    val pen = Pen()
    //with
    with(pen, {
        color = "red"
        width = 2f
        round = true
    })
    pen.write()

    //apply
    pen.apply {
        color = "gray"
        width = 6f
        round = false
        write()
    }
}

责任链模式

介绍


职责链模式(Chain of Responsibility Pattern,职责链模式):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。职责链模式是一种对象行为型模式。职责链模式结构的核心在于引入了一个抽象处理者。

重点:上一个处理对象必须含有下一个处理对象的引用,形成一个单向链表。


角色


  • Handler(抽象处理者):定义一个处理请求的抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象,作为其对下家的引用。通过该引用,处理者可以连成一条链。

  • ConcreteHandler(具体处理者):它是抽象处理者的子类,可以处理用户请求,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象,以便请求的转发。


场景


安卓实例,比如,事件分发机制。在View、ViewGroup、Activity中都有机会处理OnTouchEvent请求。

例子:主任、副董事长、董事长有不同的审批金额的权利,当超过自己额度审批范围,就像上级提交。

class Client {
    public static void main(String[] args) {
        ApproverHander little, middle, high;
        little = new Director("张三");
        middle = new VicePresident("李四");
        high = new President("王五");

        //创建职责链
        little.setSuccessor(middle);
        middle.setSuccessor(high);

        //创建采购单
        PurchaseRequest pr1 = new PurchaseRequest(45000);
        little.processRequest(pr1);

        PurchaseRequest pr2 = new PurchaseRequest(60000);
        little.processRequest(pr2);

        PurchaseRequest pr3 = new PurchaseRequest(160000);
        little.processRequest(pr3);
    }
}

//采购单:请求类
class PurchaseRequest {
    private double amount;  //采购金额

    public PurchaseRequest(double amount) {
        this.amount = amount;
    }
    public void setAmount(double amount) {
        this.amount = amount;
    }
    public double getAmount() {
        return this.amount;
    }
}

//审批者类:抽象处理者
abstract class ApproverHander {
    
    protected ApproverHander hander; //定义后继对象
    protected String name; //审批者姓名

    public ApproverHander(String name) {
        this.name = name;
    }
    //设置后继者
    public void setSuccessor(ApproverHander hander) {
        this.hander = hander;
    }
    //抽象请求处理方法
    public abstract void processRequest(PurchaseRequest request);
}

//主任类:具体处理者
class Director extends ApproverHander {

    public Director(String name) {
        super(name);
    }

    //具体请求处理方法
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 50000) {
            System.out.println("主任" + this.name + "审批金额:" + request.getAmount());  //处理请求
        } else {
            this.hander.processRequest(request);  //转发请求
        }
    }
}

//副董事长类:具体处理者
class VicePresident extends ApproverHander {
    public VicePresident(String name) {
        super(name);
    }

    //具体请求处理方法
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 100000) {
            System.out.println("副董事长" + this.name + "审批金额:" + request.getAmount());  //处理请求
        } else {
            this.hander.processRequest(request);  //转发请求
        }
    }
}

//董事长类:具体处理者
class President extends ApproverHander {
    public President(String name) {
        super(name);
    }

    //具体请求处理方法
    public void processRequest(PurchaseRequest request) {
            System.out.println("董事长" + this.name + "审批金额:" + request.getAmount());  //处理请求
       
    }
}	

和观察者模式区别


受众数量不同。观察者广播链式可以 1:N 的方式广播,而责任链则要求是的 1:1 的传递,必然有一个且只有一个类完成请求的处理;

请求内容不同。观察者广播链中的信息可以在传播中改变,但是责任链中的请求是不可改变的;

处理逻辑不通。观察者广播链主要用于触发联动动作,而责任链则是对一个类型的请求按照既定的规 则进行处理。


装饰模式

介绍


装饰模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。

装饰模式是一种用于替代继承的技术,它通过一种无须定义子类的方式来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。在装饰模式中引入了装饰类,在装饰类中既可以调用待装饰的原有类的方法,还可以增加新的方法,以扩充原有类的功能。


角色


Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。

ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。

Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。

ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。

装饰设计模式一般情况都是把类对象作为构造参数传递。在不使用的继承的方式下,采用装饰设计模式可以扩展一个对象的功能,可以使一个对象变得越来越强大。


场景


例子:在铺了地板的毛坯房上进行装饰:

public class Client {
    public static void main(String args[]) {
        Home home, homeTake; //使用抽象构件定义
        home = new Floor(); //定义具体构件
        homeTake = new TakeHomeDecorator(home); //定义装饰后的构件
        homeTake.display();
    }
}

//抽象界面构件类
abstract class Home {
    public abstract void display();
}

//具体构件类
class Floor extends Home {
    public void display() {
        System.out.println("毛坯房铺了地板");
    }
}

//抽象装饰类
class HomeDecorator extends Home {
    private Home component;  //维持对抽象构件类型对象的引用
    
    public HomeDecorator(Home component){//注入抽象构件类型的对象
        this.component = component;
    }
    public void display() {
        component.display();
    }
}

//具体装饰类
class TakeHomeDecorator extends HomeDecorator {

    public TakeHomeDecorator(Home component) {
        super(component);
    }

    public void display() {
        super.display();
        this.setFurniture();
    }

    public void setFurniture() {
        System.out.println("搬进去很多家具");
    }
}

Java和Kotlin


java:

class Client {
    public static void main(String[] args) {
        Panda panda = new Panda();
        BambooFood bambooFood = new BambooFood(panda);
        CarrotFood carrotFood = new CarrotFood(bambooFood);
        //什么都没有,不知道吃啥?
        //吃竹子
        //吃葫芦卜
        carrotFood.eat();
    }
}

/**
 * 抽象组件
 */
interface Animal {
    void eat();
}

/**
 * 被装饰者
 */
class Panda implements Animal {
    @Override
    public void eat() {
        System.out.println("什么都没有,不知道吃啥?");
    }
}

/**
 * 装饰着组件
 */
abstract class Food implements Animal {
    Animal animal;

    public Food(Animal animal) {
        this.animal = animal;
    }

    @Override
    public void eat() {
        animal.eat();
    }
}

/**
 * 具体装饰
 */
class BambooFood extends Food {

    public BambooFood(Animal animal) {
        super(animal);
    }

    @Override
    public void eat() {
        super.eat();
        System.out.println("吃竹子");
    }
}

/**
 * 具体装饰
 */
class CarrotFood extends Food {

    public CarrotFood(Animal animal) {
        super(animal);
    }

    @Override
    public void eat() {
        super.eat();
        System.out.println("吃葫芦卜");
    }
}

kotlin

/**
 * 抽象组件
 */
interface Animal {
    fun eat()
}

/**
 * 被装饰者
 */
class Panda : Animal {
    override fun eat() {
        println("什么都没有,不知道吃啥?")
    }
}

fun Panda.bamboo(decorator: () -> Unit){
    eat()
    println("吃竹子")
    decorator()
}

fun Panda.carrot(decorator: () -> Unit){
    println("吃胡萝卜")
    decorator()
}

fun main(){
    //什么都没有,不知道吃啥?
    //吃竹子
    //吃胡萝卜
    Panda().run {
        bamboo {
            carrot {  }
        }
    }
}

安卓实例


ListView中的HeaderViewListAdapter,添加头部和底部。

ContextWrapper。


模板方法模式

介绍


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

其核心是抽象类和其中的模板方法的设计。父类一般都是流程和通用部分的封装,子类一般都是具体的功能和逻辑。

钩子:用来控制父类的流程,比如:插件化开发hook启动流程。


场景


模版和钩子,比如吃饭:点餐、吃东西、充卡、买单,充卡可以自由选择

public class Client {
    public static void main(String[] args) {
        PeopleEat h1 = new PeopleEat();
        h1.setMoney(true);
        h1.havaEat();
    }
}

abstract class EatModel {

    //钩子方法,默认会充钱
    protected boolean isAdd(){
        return true;
    }
    protected abstract void orderFood();

    protected abstract void eatMeal();

    protected abstract void addMoney();
    
    protected abstract void payBill();
    
    final public void havaEat() {
        this.orderFood();
        this.eatMeal();
        if(this.isAdd()){
            this.addMoney();
        }
        this.payBill();
    }
}

class PeopleEat extends EatModel {

    private boolean addMoneyFlag = true;
    
    @Override
    protected void addMoney() {
        System.out.println("充值200元...");
    }

    @Override
    protected void payBill() {
        System.out.println("买单离开...");
    }

    @Override
    protected void orderFood() {
        System.out.println("点了烤肉...");
    }

    @Override
    protected void eatMeal() {
        System.out.println("开始烤肉啦...");
    }

    @Override
    protected boolean isAdd() {
        return this.addMoneyFlag;
    }

    public void setMoney(boolean isAdd){
        this.addMoneyFlag = isAdd;
    }
}

安卓实例


Activity的生命周期采用了模板方法模式:首先都是继承自Activity,而且所有要自己定义写的Activity的生命周期的流程都是一样的,每个Activity可以设置不同的界面,可以实现自己的具体交互逻辑。

AsyncTask

开发中BaseActivity


策略设计模式

介绍


策略模式(Strategy Pattern):定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为型模式。

策略模式的主要目的是将算法的定义与使用分开,将算法的定义放在专门的策略类中,每一个策略类封装了一种实现算法。在出现新的算法时,只需要增加一个新的实现了抽象策略类的具体策略类即可。


角色


Context(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。

Strategy(抽象策略类):它为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。

ConcreteStrategy(具体策略类):它实现了在抽象策略类中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。


场景


景区门票,原始票价,学生票价,老人票价

public class Client {
    public static void main(String[] args){
        ParkTicket pt = new ParkTicket();
        double originalPrice = 100;

        pt.setPrice(originalPrice);
        System.out.println("原始价为:" + originalPrice);

        Discount discount = new StudentDiscount();
        pt.setDiscount(discount); //注入折扣对象
        System.out.println("折后价为:" + pt.getPrice());
    }
}

//环境类:公园票价
class ParkTicket {
    private double price;
    private Discount discount; //维持一个对抽象折扣类的引用

    public void setPrice(double price) {
        this.price = price;
    }

    //注入一个折扣类对象
    public void setDiscount(Discount discount) {
        this.discount = discount;
    }

    public double getPrice() {
        //调用折扣类的折扣价计算方法
        return discount.calculate(this.price);
    }
}

//抽象策略类:折扣类
interface Discount {
    public double calculate(double price);
}

//具体策略类:学生票折扣类
class StudentDiscount implements Discount {
    public double calculate(double price) {
        System.out.println("学生票:");
        return price * 0.8;
    }
}

//具体策略类:老人票折扣类
class OldManDiscount implements Discount {
    public double calculate(double price) {
        System.out.println("老人票:");
        return price - 10;
    }
}
    

策略模式定义了一系列算法,并将每一个算法封装起来,而且是他们之间可以相互切换。


安卓实例


第三方的:Glide的缓存策略,ImageLoader的生成图片文件的命名策略,timber日志打印工具的策略,OKhttp部分

源码里面:属性动画setInterpolator差值器;RecyclerView:setLayoutManager可以是ListView样式或者是GirdView样式等等。


观察者模式

场景


观察者是汽车,根据被观察者红路灯,作出反应。

public class Client {
    public static void main(String[] args){
        //观察者
        Observer bigCar = new BigCar();
        Observer smallCar = new SmallCar();
        //被观察者
        TrafficLight trafficLight = new TrafficLight();
        //关联
        trafficLight.addObserver(bigCar);
        trafficLight.addObserver(smallCar);
        //目标有变化,看看观察者怎么办
        trafficLight.havaRed();
        trafficLight.havaGreen();
    }
}

//被观察者
interface Observable {
    //增加一个观察者
    void addObserver(Observer observer);
    //删除一个观察者
    void deleteObserver(Observer observer);
    //通知观察者
    void notifyObservers(String context);
}

//观察者
interface Observer {
    //一发现􏰀人有动静,自己也要行动起来
    void update(String context);
}

//被观察者
class TrafficLight implements Observable {

    //存放所有的观察者
    private ArrayList<Observer> observerList = new ArrayList<>();

    //增加观察者
    public void addObserver(Observer observer) {
        this.observerList.add(observer);
    }

    //删除观察者
    public void deleteObserver(Observer observer) {
        this.observerList.remove(observer);
    }

    //通知所有的观察者
    public void notifyObservers(String context) {
        for (Observer observer : observerList) {
            observer.update(context);
        }
    }
    
    public void havaRed() {
        System.out.println("红灯..."); //通知所有的观察者
        this.notifyObservers("红灯停车啦");
    }
    
    public void havaGreen() {
        System.out.println("绿灯...");
        this.notifyObservers("绿灯开车啦");
    }
}

//观察者
class BigCar implements Observer {
    public void update(String str) {
        System.out.println(str);
        this.makeCar(str);
    }
    private void makeCar(String reportContext) {
        System.out.println("我是大汽车--->" + reportContext);
    }
}

//观察者
class SmallCar implements Observer {
    public void update(String str) {
        System.out.println(str);
        this.makeCar(str);
    }
    private void makeCar(String reportContext) {
        System.out.println("我是小汽车--->" + reportContext);
    }
}

推拉模式


推拉模式:上面是推模式,即被观察者变化的时候,推送给观察者。拉模式,即被观察者变化的时候,观察者主动查看下被观察者。可以分开使用,也可以结合使用。


原生API


继承原生API实现

import java.util.Observable;
import java.util.Observer;

public class Client {
    public static void main(String[] args){
        //观察者
        Observer bigCar = new BigCar();
        Observer smallCar = new SmallCar();
        //被观察者
        TrafficLight trafficLight = new TrafficLight();
        //关联
        trafficLight.addObserver(bigCar);
        trafficLight.addObserver(smallCar);
        //目标有变化,看看观察者怎么办
        trafficLight.havaRed();
        trafficLight.havaGreen();
    }
}

//被观察者
class TrafficLight extends Observable {

    public void havaRed() {
        System.out.println("红灯...");
        super.setChanged();
        super.notifyObservers("红灯停车啦");
    }
    
    public void havaGreen() {
        System.out.println("绿灯...");
        super.setChanged();
        super.notifyObservers("绿灯开车啦");
    }
}

//观察者
class BigCar implements Observer {
    private void makeCar(String reportContext) {
        System.out.println("我是大汽车--->" + reportContext);
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println(arg.toString());
        this.makeCar(arg.toString());
    }
}

//观察者
class SmallCar implements Observer {
    private void makeCar(String reportContext) {
        System.out.println("我是小汽车--->" + reportContext);
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println(arg.toString());
        this.makeCar(arg.toString());
    }
}

安卓实例


ListView的Adapter的setDataChange方法。给Adapter注册一个mDataSetObserver。

mAdapter.registerDataSetObserver(mDataSetObserver); 

代理模式

静态代理


目标接口、代理对象、被代理的对象。

/**
 * 银行办理业务 - 目标接口(业务)
 */
public interface IBank {
    /*** 申请办卡*/
    public void applyBank();

    /*** 挂失*/
    public void lostBank();
}

/**
 * 银行办理业务 - 代理对象 - 银行的业务员
 */
public class BankWorker implements IBank{
    private IBank bank;
    /**
     * 持有被代理的对象
     * @param bank
     */
    public BankWorker(IBank bank){
        this.bank = bank;
    }

    @Override
    public void applyBank() {
        System.out.println("开始受理");
        bank.applyBank();
        System.out.println("操作完毕");
    }

    @Override
    public void lostBank() {
        System.out.println("开始受理");
        bank.lostBank();
        System.out.println("操作完毕");
    }
}

/**
 * 银行办理业务 - 被代理的对象 - 我们
 */
public class Man implements IBank {
    private String name;

    public Man(String name) {
        this.name = name;
    }

    /**
     * 自己的一些操作
     */
    @Override
    public void applyBank() {
        System.out.println(name + " 申请办卡");
    }

    @Override
    public void lostBank() {
        System.out.println(name + " 申请挂失");
    }
}

public class Client {
    public static void main(String[] args){
        Man man = new Man("张三");
        BankWorker bankWorker = new BankWorker(man);
        bankWorker.applyBank();
    }
}

动态代理


形式

Proxy.newProxyInstance(
    IBank.class.getClassLoader(),//ClassLoader
    new Class<?>[]{IBank.class},//目标接口
    null//InvocationHandler-关键
);

代码

/**
 * 银行办理业务 - 动态代理 - InvocationHandler
 */
public class BankInvocationHandler implements InvocationHandler{
    /**
     * 被代理的对象
     */
    private Object mObject;

    public BankInvocationHandler(Object object){
        this.mObject = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 执行方法 ,目标接口调用的方法都会来到这里面
        // System.out.println("methodName = "+method.getName());
        System.out.println("开始受理");
        // System.out.println("params = "+args.toString());
        // 调用被代理对象的方法,这里其实调用的就是  man 里面的 applyBank 方法
        Object voidObject = method.invoke(mObject,args);
        System.out.println("操作完毕");
        return voidObject;
    }
}

public class Client {
    public static void main(String[] args) {
        Man man = new Man("张三");

        IBank bank =
                // 返回的是 IBank 的一个实例对象,这个对象是由 Java 给我们创建的 ,调用的是 jni
                (IBank) Proxy.newProxyInstance(
                        IBank.class.getClassLoader(), // ClassLoader
                        new Class<?>[]{IBank.class}, // 目标接口
                        new BankInvocationHandler(man) // InvocationHandler (这个类是关键)
                );
        // 当调用这个方法的时候会来到 BankInvocationHandler 的 invoke 方法
        bank.applyBank();
        bank.lostBank();
        bank.extraBank();
    }
}

/**
 * 银行办理业务 - 目标接口(业务)
 */
public interface IBank {
    /**
     * 申请办卡
     */
    public void applyBank();

    /**
     * 挂失
     */
    public void lostBank();

    /**
     * 额外业务
     */
    public void extraBank();
}

/**
 * 银行办理业务 - 被代理的对象 - 我们
 */
public class Man implements IBank {
    private String name;

    public Man(String name){
        this.name = name;
    }

    /**
     * 自己的一些操作
     */
    @Override
    public void applyBank() {
        System.out.println(name + " 申请办卡");
    }

    @Override
    public void lostBank() {
        System.out.println(name + " 申请挂失");
    }

    @Override
    public void extraBank() {
        System.out.println(name + " 额外业务");
    }
}

开发用到的地方


Android 插件化架构之绕过 AndroidManifest 检测(动态代理)
Android 数据库实现数据的懒加载(静态代理)
Android MVP 架构设计(静态代理和动态代理)
Android Xutils 实现 View 事件注入(动态代理)
Android Retrofit 的 create 创建接口对象 (动态代理)
Android Framework 层的 AMS
Android Framework 层的 Binder 驱动

Retrofit的create

public <T> T create(final Class<T> service) {
    // 验证当前类是否是接口
    Utils.validateServiceInterface(service);

    //有需要的话做方法缓存?
    if (validateEagerly) {
        eagerlyValidateMethods(service);
    }

    // 动态代理设计模式
    return (T) Proxy.newProxyInstance(service.getClassLoader(),
            new Class<?>[] { service }, new InvocationHandler() {

                private final Platform platform = Platform.get();

                @Override
                public Object invoke(Object proxy, Method method,
                        Object... args) throws Throwable {
                    //如果调用的方法是Object的
                    if (method.getDeclaringClass() == Object.class) {
                        return method.invoke(this, args);
                    }
                    // //默认进不来这个if ,平台判断 android java8 ios
                    if (platform.isDefaultMethod(method)) {
                        return platform.invokeDefaultMethod(method,
                                service, proxy, args);
                    }

                    // 重点*具体执行细节
                    // method:就是我们调用的具体的方法(例如:login方法) 去解析方法属性和参数属性吧?
                    ServiceMethod serviceMethod = loadServiceMethod(method);
                    // 解析完成之后,调用OKHttp框架执行请求
                    OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
                    // 这个最终是 ExecutorCallAdapterFactory 里面的 CallAdapter 所以最终返回的是 ExecutorCallbackCall
                    return serviceMethod.callAdapter.adapt(okHttpCall);
                }
            });
}

自己实现create的思路

public <T> T create(Class<T> clazz){
    // 动态代理
    return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
            new Class<?>[]{clazz}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    Log.e("TAG",method.getName());
                    // 如果要实现 Retrofit 一样的代码应该怎么办?
                    // 1. 解析方法的所有注解 比如 POST GET FormUrlEncoded 等等
                    // 2. 解析参数的所有注解 比如 FieldMap Part PartMap 等等
                    // 3. 封装成 Call 对象
                    // 4.返回的 Call 对象
                    return "返回";
                }
            });
}

通过Retrofit.create(class)方法创建出Service interface的实例,从而使得Service中配置的方法变得可用,这是Retrofit代码结构的核心。

Retrofit.create(class)方法内部,使用Proxy.newProxyInstance()方法创建Service实例。create方法会为参数中的interface创建一个对象,这个对象实现了interface中的每一个方法,并且每个方法的实现都是类似的:调用对象实例内部的一个InvocationHandler成员变量的invoke()方法,并把自己的方法信息传递进去。实质上就是动态代理:interface中的方法全部由一个另外设定的InvocationHandler对象来进行代理操作。并且,这些方法的具体实现是在运行时生成interface实例时才确定的,而不是在编译时。

invoke()方法中创建interface实例,有三行关键代码:

1、ServiceMethod的创建:

ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>)loadServiceMethod(method);

这行代码负责读取interface中原方法的信息,包括返回值、方法注解、参数类型、参数注解,并将这些信息做初步分支。

2、OkHttpCall的创建

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

OkHttpCall是retrofit2.Call的子类。这行代码负责将ServiceMethod封装进retrofit2.Call对象,这个对象可以在需要的时候,例如enqueue()方法被调用的时候,利用ServiceMethod中包含的信息来创建一个okhttp3.Call对象,并调用这个okhttp3.Call对象来进行网络请求的发起,然后对结果进行预处理,如类型转换。

3、adapt()方法

return serviceMethod.callAdapter.adapt(okHttpCall);

这个方法会使用ServiceMethod中的callAdapter对象来把okHttpCall对象进行转换,生成一个新的retrofit2.Call对象,在这个新的Call对象中,后台线程发起的请求,会在相应返回后,从主线程中调用回调方法,实现线程的自动切换。

另外这个方法不止可以生成新的retrofit2.Call对象,也可以生成别的类型对象,例如RaJava的Obervable,来让Retrofit可以和RaJava结合使用。



文章作者:
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 !
  目录