android Java开发设计模式及在android中的应用解析

秒懂MVVM模式在Android中的应用 什么是MVVM模式 上世纪90年代,软件设计模式的超级大神Martin Fowler在MVC模式的基础上提出了MVP模式。经过若干年的发展,MVP模式又衍生出了MVVM模式。MVVM(Model-View-ViewModel)模式有助于将业务逻辑与UI完全分开,这为单元测试和后期代码维护提供了极大的便利。 MVC、MVP和MVVM之间的关系 搞清楚MVC、MVP和MVVM之间的关系,对于我们理解和应用MVVM模式有非常大的帮助。 MVC和MVP的关系 MVP模式是从经典的MVC模式演变而来的。因此,它们的基 阅读详情

android Java开发设计模式及在android中的应用解析

什么是设计模式:

  • 可以用一句话概括设计模式———设计模式是一种利用OOP的封闭、继承和多态三大特性,同时在遵循单一职责原则、开闭原则、里氏替换原则、迪米特法则、依赖倒置原则、接口隔离原则及合成/聚合复用原则的前提下,被总结出来的经过反复实践并被多数人知晓且经过分类和设计的可重用的软件设计方式。

设计模式的六大原则

  • 1、开闭原则(Open Close Principle)

    开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

  • 2、里氏代换原则(Liskov Substitution Principle)

    里 氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里 氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现 抽象化的具体步骤的规范。

  • 3、依赖倒转原则(Dependence Inversion Principle)

    这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。

  • 4、接口隔离原则(Interface Segregation Principle)

    这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

  • 5、迪米特法则(最少知道原则)(Demeter Principle)

    为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

  • 6、合成复用原则(Composite Reuse Principle)

    原则是尽量使用合成/聚合的方式,而不是使用继承。

部分Java设计模式在android中的使用

如果你没有认证学习过Java的设计模式,不理解托管语言的OOP设计方法,可能你的应用变得很结构化,对于项目管理、架构扩展来说将会存在很多问题,参看了目前国内很多应用发现很多代码完全就不是一个Java程序员写出来的,虽然能用但是这样设计对于日后的维护等方面将会有很严重的问题.

1、单例模式

单例模式应该是日常使用最为广泛的一种模式了。他的作用是确保某个类只有一个实例,避免产生多个对象消耗过多的资源。比如对数据库的操作时,就可以使用单例模式。
介绍单例模式使用方法的文章有很多,可以参见你真的用对单例模式了吗?

优点:
(1)由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁的创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
(2)单例模式可以避免对资源的多重占用,例如一个文件操作,由于只有一个实例存在内存中,避免对同一资源文件的同时操作。
(3)单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如,可以设计一个单例类,负责所有数据表的映射处理。

缺点:
(1)单例模式一般没有接口,扩展很困难,若要扩展,只能修改代码来实现。
(2)单例对象如果持有Context,那么很容易引发内存泄露。此时需要注意传递给单例对象的Context最好是Application Context。

2、Builder建造者模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

使用场景:
(1)相同的方法,不同的执行顺序,产生不同的事件结果时。
(2)多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
(3)产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个使用建造者模式非常适合。

优点:
(1)良好的封装性,使用建造者模式可以使客户端不必知道产品内部组成细节。
(2)建造者独立,容易扩展。
缺点:
(1)会产生多余的Builder对象及Director对象,消耗内存。

简单实现
public interface Builder {

  //创建部件A  比如创建汽车车轮
  void buildPartA(); 
  //创建部件B   比如创建汽车方向盘
  void buildPartB(); 
  //创建部件C   比如创建汽车发动机
  void buildPartC();
  //返回最后组装成品结果 (返回最后装配好的汽车)
  Product getResult();

}
//Director 类,负责制造
public class Director {

  private Builder builder;

  public Director( Builder builder ) { 
    this.builder = builder; 
  } 
  // 将部件partA partB partC最后组成复杂对象
  //这里是将车轮 方向盘和发动机组装成汽车的过程
  public void construct() { 
    builder.buildPartA();
    builder.buildPartB();
    builder.buildPartC();

  }

}

public class ConcreteBuilder implements Builder {

  Part partA, partB, partC; 
  public void buildPartA() {
    //这里是具体如何构建partA的代码
  }; 
  public void buildPartB() { 
    //这里是具体如何构建partB的代码
  }; 
   public void buildPartC() { 
    //这里是具体如何构建partB的代码
  }; 
   public Product getResult() { 
    //返回最后组装成品结果
  }; 
}

public interface Product { }//产品

public interface Part { }//部件

//调用
ConcreteBuilder builder = new ConcreteBuilder();
Director director = new Director( builder ); 

director.construct(); 
Product product = builder.getResult();

现实开发中,Director一般被省略。而直接使用一个Builder来进行对象的组装,这个Builder通常为链式调用,他是将setter方法返回自身。代码大致如下:

new TestBuilder().setA("A").setB("B").create();

3、工厂方法模式

定义一个用于创建对象的接口,让子类决定实例化那个类。在任何需生成复杂对象的地方,都可以使用工厂方法模式。复杂对象适合使用工厂模式,用new就可以完成创建的对象无需使用工厂模式。

优点:
1.工厂方法模式完全符合设计原则,降低了对象之间的耦合。高层模块只需要知道产品的抽象类,其他的实现都不需要关心。
2.良好的封装性,代码结构清晰。扩展性好。
缺点:
每次我们为工厂方法模式添加新的产品时就要编写一个新的产品类。同时还要引入抽象层,这必然会导致类结构的复杂化,所以,在某些情况比较简单时,是否要使用工厂模式,需要设计者权衡利弊了。

简单实现
public abstract class Product {
    /**
     * 产品类的抽象方法
     * 由具体的产品类去实现
     * */
    public abstract void method();
}

public class ConcreteProductA extends Product {

    @Override
    public void method() {
        System.out.println("我是产品A");
    }
}

public class ConcreteProductB extends Product {

    @Override
    public void method() {
        System.out.println("我是产品B");
    }
}

public abstract class Factory {
    /**
     * 抽象工厂方法
     * 具体由子类实现
     * 
     * @return 具体的产品对象
     * */
    public abstract Product createProduct();
}

public class ConcreteFactory extends Factory {
    /**
     * 具体工厂类
     * */
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

public class Client {
    public static void main(String[] args) {
        Factory factory = new ConcreteFactory();
        Product product = factory.createProduct();
        product.method();
    }
}

上面这种方式可能不是很灵活,可以利用反射实现,如下:

public abstract class Factory {
    /**
     * 抽象工厂方法
     * 具体由子类实现
     * 
     * @param clz 产品对象类类型
     * 
     * @return 具体的产品对象
     * */
    public abstract <T extends Product> T createProduct(Class<T> clz);
}

public class ConcreteFactory extends Factory {
    /**
     * 具体工厂类
     * */
    @SuppressWarnings("unchecked")
    @Override
    public <T extends Product> T createProduct(Class<T> clz) {
        Product product = null;
        try {
            product = (Product) Class.forName(clz.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T)product;
    }
}

public class Client {
    public static void main(String[] args) {
        Factory factory = new ConcreteFactory();
        Product product = factory.createProduct(ConcreteProductB.class);
        product.method();
    }
}

//如果我们的工厂只有一个,我们可以进行简化,这种方式又称为简单工厂模式或者静态工厂模式。
public class Factory {
    /**
     * 抽象工厂方法
     * 具体由子类实现
     * 
     * @param clz 产品对象类类型
     * 
     * @return 具体的产品对象
     * */
    public static <T extends Product> T createProduct(Class<T> clz) {
        Product product = null;
        try {
            product = (Product) Class.forName(clz.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T)product;
    }
}

4、策略模式

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

使用场景:
1.针对同一类型问题的多种处理方式,仅仅是具体行为有差别时。
2.需要安全地封装多种同一类型的操作时。
3.出现同一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体子类时。

简单实现

需求:计算图书价格,初级会员没有折扣,中级会员打9折,高级会员打8折。如果一般写法,应该是if-else判断他是什么级别的会员,在计算相应的折扣。下面使用策略模式来进行实现。

public interface MemberStrategy {
    /**
     * 计算图书的价格
     * @param booksPrice    图书的原价
     * @return    计算出打折后的价格
     */
    public double calcPrice(double booksPrice);
}

public class PrimaryMemberStrategy implements MemberStrategy{
    /**
     * 初级会员折扣
     */
    @Override
    public double calcPrice(double booksPrice) {
        System.out.println("对于初级会员的没有折扣");
        return booksPrice;
    }
}

public class IntermediateMemberStrategy implements MemberStrategy{
    /**
     * 中级会员折扣
     */
    @Override
    public double calcPrice(double booksPrice) {
        System.out.println("对于中级会员的折扣为10%");
        return booksPrice * 0.9;
    }
}

public class AdvancedMemberStrategy implements MemberStrategy{
    /**
     * 高级会员折扣
     */
    @Override
    public double calcPrice(double booksPrice) {
        System.out.println("对于高级会员的折扣为20%");
        return booksPrice * 0.8;
    }
}

public class Price {
    //持有一个具体的策略对象
    private MemberStrategy strategy;
    /**
     * 构造函数,传入一个具体的策略对象
     * @param strategy    具体的策略对象
     */
    public Price(MemberStrategy strategy){
        this.strategy = strategy;
    }

    /**
     * 计算图书的价格
     * @param booksPrice    图书的原价
     * @return    计算出打折后的价格
     */
    public double quote(double booksPrice){
        return this.strategy.calcPrice(booksPrice);
    }
}

public class Client {

    public static void main(String[] args) {
        //选择并创建需要使用的策略对象
        MemberStrategy strategy1 = new AdvancedMemberStrategy();
        //创建环境
        Price price = new Price(strategy1);
        //计算价格
        double quote = price.quote(300);
        System.out.println("图书的最终价格为:" + quote);
    }

}

//结果
//对于高级会员的折扣为20%
//图书的最终价格为:240.0

5、责任链模式

责任链模式是行为型设计模式之一,它使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

1.多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
2.在请求处理者不明确的情况下向多个对象中的一个提交请求。
3.需要动态指定一组对象处理请求。

简单实现

这个例子我觉得很贴切。我们在公司有各种原因需要报销费用,首先我们要找我们的上级领导去审批,报销额度如果在领导的权限范围内,那就审批通过,否则领导在找自己的上级去审批,以此类推。

//抽象领导类
public abstract class Leader {
    /**
     * 上级领导处理者
     */
    protected Leader nextHandler;

    /**
     * 处理报账请求
     * 
     * @param money 能批复的报账额度 
     * 
     */
    public final void handleRequest(int money){
        System.out.println(getLeader());
        if(money <=limit()){
            handle(money);
        }else{
            System.out.println("报账额度不足,提交领导");
            if(null != nextHandler){
                nextHandler.handleRequest(money);
            }
        }
    }

    /**
     * 自身能批复的额度权限
     * 
     * @return 额度
     */
    public abstract int limit();

    /**
     * 处理报账行为
     * 
     * @param money 具体金额
     */
    public abstract void handle(int money);

    /**
     * 获取处理者
     * 
     * @return 处理者
     */
    public abstract String getLeader();
}

//组长(额度1000):
public class GroupLeader extends Leader{

    @Override
    public int limit() {
        return 1000;
    }

    @Override
    public void handle(int money) {
        System.out.println("组长批复报销"+ money +"元");
    }

    @Override
    public String getLeader() {
        return "当前是组长";
    }

} 

//主管(额度5000):
public class Director extends Leader{

    @Override
    public int limit() {
        return 5000;
    }

    @Override
    public void handle(int money) {
        System.out.println("主管批复报销"+ money +"元");
    }

    @Override
    public String getLeader() {
        return "当前是主管";
    }

}

//经理(额度10000):
public class Manager extends Leader{

    @Override
    public int limit() {
        return 10000;
    }

    @Override
    public void handle(int money) {
        System.out.println("经理批复报销"+ money +"元");
    }

    @Override
    public String getLeader() {
        return "当前是经理";
    }

}

//老板(额度…):
public class Boss extends Leader{

    @Override
    public int limit() {
        return Integer.MAX_VALUE;
    }

    @Override
    public void handle(int money) {
        System.out.println("老板批复报销"+ money +"元");
    }

    @Override
    public String getLeader() {
        return "当前是老板";
    }

}

//发起申请:
public class Client {
    public static void main(String[] args) {
        //构造各个领导对象
        GroupLeader groupLeader = new GroupLeader();
        Director director = new Director();
        Manager manager = new Manager();
        Boss boss = new Boss();
        //设置上级领导处理者对象
        groupLeader.nextHandler = director;
        director.nextHandler = manager;
        manager.nextHandler = boss;

        //发起报账申请
        groupLeader.handleRequest(8000);

    }
}

//结果:
当前是组长
报账额度不足,提交领导
当前是主管
报账额度不足,提交领导
当前是经理
经理批复报销8000元

责任链模式非常灵活,请求的发起可以从责任链的任何一个节点开始,也可以改变内部的传递规则。比如主管不在,我们完全可以跨过主管直接从组长那里转到经理。

对于责任链中的一个处理者对象,有两个行为。一是处理请求,二是将请求传递到下一节点,不允许某个处理者对象在处理了请求后又将请求传送给上一个节点的情况。
对于一条责任链来说,一个请求最终只有两种情况。一是被某个处理对象所处理,另一个是所有对象均未对其处理,对于前一种情况我们称为纯的责任链模式,后一种为不纯的责任链。实际中大多为不纯的责任链。

Android源码中的责任链模式

View事件的分发处理

ViewGroup事件投递的递归调用就类似于一条责任链,一旦其寻找到责任者,那么将由责任者持有并消费掉该次事件,具体体现在View的onTouchEvent方法中返回值的设置,如果返回false,那么意味着当前的View不会是该次的责任人,将不会对其持有;如果返回true,此时View会持有该事件并不再向外传递。

1.优点
可以对请求者和处理者的关系解耦,提高代码的灵活性。
2.缺点
每次都需要对链中请求处理者遍历,如果处理者太多那么遍历必定会影响性能,特别是在一些递归调用者中,要慎用。

6、观察者模式

观察者模式是一个使用率非常高的模式,它最常用在GUI系统、订阅–发布系统。因为这个模式的一个重要作用就是解耦,将被观察者和观察者解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。比如安卓的开源项目EventBus、Otto、AndroidEventBus等事件总线类的和RxJava响应式编程其核心都是使用观察者模式。

观察者模式是一种行为类模式,它定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

(1)关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系。
(2)事件多级触发场景。
(3)跨系统的消息交换场景,如消息队列、事件总线的处理机制。

简单实现

这里举一个追剧的例子,平常为了不错过最新的电视剧我们会订阅或关注这个电视剧,当电视剧更新后会第一时间推送给我们,下来就简单实现一下。

//抽象观察者类
/**
 *  抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己
 */
public interface Observer {
    /**
     *  有更新
     *  
     *  @param message 消息
     */
    public void update(String message);

}

/**
 * 抽象被观察者类
 */
public interface Observable {

    /**
     * 推送消息
     * 
     * @param message 内容
     */
    void push(String message);

    /**
     * 订阅
     * 
     * @param observer 订阅者
     */
    void register(Observer observer);
}

/**
 * 具体的观察者类,也就是订阅者
 */
public class User implements Observer {

    @Override
    public void update(String message) {
        System.out.println(name + "," + message + "更新了!");

    }

    // 订阅者的名字
    private String name;

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

/**
 *  具体的被观察者类,也就是订阅的节目
 */
public class Teleplay implements Observable{

    private List<Observer> list = new ArrayList<Observer>();//储存订阅者

    @Override
    public void push(String message) {
        for(Observer observer:list){
            observer.update(message);
        }
    }

    @Override
    public void register(Observer observer) {
        list.add(observer);
    }

}

public class Client {
    public static void main(String[] args) {
        //被观察者,这里就是用户订阅的电视剧
        Teleplay teleplay = new Teleplay();
        //观察者,这里就是订阅用户
        User user1 = new User("小明");
        User user2 = new User("小光");
        User user3 = new User("小兰");
        //订阅
        teleplay.register(user1);
        teleplay.register(user2);
        teleplay.register(user3);
        //推送新消息
        teleplay.push("xxx电视剧");
    }
}

小明,xxx电视剧更新了!
小光,xxx电视剧更新了!
小兰,xxx电视剧更新了!
Android源码中的观察者模式

当ListView的数据发生变化时,调用Adapter的notifyDataSetChanged函数,这个函数又会调用DataSetObservable的notifyChanged函数,这个函数会调用所有观察者 (AdapterDataSetObserver) 的onChanged方法。这就是一个观察者模式!

1.优点
(1)观察者和被观察者之间是抽象耦合,应对业务变化。
(2)增强系统的灵活性和可扩展性。
2.缺点
在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。

7、访问者模式

访问者模式,顾名思义使用了这个模式后就可以在不修改已有程序结构的前提下,通过添加额外的“访问者”来完成对已有代码功能的提升。

1.定义
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。
2.使用场景
(1)对象结构比较稳定,但经常需要在此对象结构上定义新的操作。
(2)需要对一个对象结构中的对象进行很多不同的且不相关的操作,而需要避免这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。

简单实现

情景:年终了,公司会给员工进行业绩考核。但是,不同领域的管理人员对于员工的评定标准不一样。现在员工有攻城狮和经理,评定者有CEO和CTO,我们假定CTO只关注攻城狮的代码量、经理的新产品数量,而CEO关注的是攻城狮的KPI和经理的KPI以及新产品数量。

/**
 * 员工基类(Element) 
 */
public abstract class Staff {
    //员工姓名
    public String name;
    //员工KPI
    public int kpi;

    public Staff(String name) {
        super();
        this.name = name;
        this.kpi = new Random().nextInt(10);
    }
    //接受Visitor的访问
    public abstract void accept(Visitor visitor);

}

/**
 * 攻城狮 
 */
public class Engineer extends Staff{

    private int codeLines;//代码数量

    public Engineer(String name) {
        super(name);
        codeLines = new Random().nextInt(10 * 10000);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    //攻城狮这一年写的代码数量
    public int getCodeLines(){
        return codeLines;
    }
}

/**
 * 经理
 */
public class Manager extends Staff{

    private int products;//产品数量

    public Manager(String name) {
        super(name);
        products = new Random().nextInt(10);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    //一年内做的产品数量
    public int getProducts(){
        return products;
    }
}

/**
*Visitor类
*/
public interface Visitor {
    /**
     * 访问攻城狮类型
     */
    public void visit(Engineer engineer);

    /**
     * 访问经理类型
     */
    public void visit(Manager manager);
}

/**
*CEO访问者
*/
public class CEOVisitor implements Visitor {

    @Override
    public void visit(Engineer engineer) {
        System.out.println("攻城狮:" + engineer.name + ", KPI:" + engineer.kpi);
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("经理:" + manager.name + ", KPI:" + manager.kpi
                + ", 新产品数量 :" + manager.getProducts());
    }

}

/**
*CTO访问类
*/
public class CTOVisitor implements Visitor {

    @Override
    public void visit(Engineer engineer) {
        System.out.println("攻城狮:" + engineer.name + ", 代码数量:" + engineer.getCodeLines());
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("经理:" + manager.name +", 产品数量 :" + manager.getProducts());
    }

}

/**
*员工报表类
*/
//员工业务报表类(ObjectStructure)
public class BusinessReport {

    List<Staff> mStaffs = new LinkedList<Staff>();

    public BusinessReport() {
        mStaffs.add(new Manager("王经理"));
        mStaffs.add(new Engineer("攻城狮-A"));
        mStaffs.add(new Engineer("攻城狮-B"));
        mStaffs.add(new Manager("李经理"));
        mStaffs.add(new Engineer("攻城狮-C"));
    }

    /**
     * 为访问者展示报表 
     * @param visitor 如CEO、CTO
     */
    public void showReport(Visitor visitor){
        for(Staff staff : mStaffs){
            staff.accept(visitor);
        }
    }
}

//Client访问
public class Client {
    public static void main(String[] args) {
        //构建报表
        BusinessReport report = new BusinessReport();
        System.out.println("===== 给CEO看报表 =====");
        //设置访问者CEO
        report.showReport(new CEOVisitor());
        System.out.println("===== 给CTO看报表 =====");
        //设置访问者CTO
        report.showReport(new CTOVisitor());
    }
}

//结果
===== 给CEO看报表 =====
经理:王经理, KPI:2, 新产品数量 :5
攻城狮:攻城狮-A, KPI:5
攻城狮:攻城狮-B, KPI:7
经理:李经理, KPI:9, 新产品数量 :8
攻城狮:攻城狮-C, KPI:1
===== 给CTO看报表 =====
经理:王经理, 产品数量 :5
攻城狮:攻城狮-A, 代码数量:26238
攻城狮:攻城狮-B, 代码数量:8282
经理:李经理, 产品数量 :8
攻城狮:攻城狮-C, 代码数量:47927
Android源码中的访问者模式

安卓中的著名开源库ButterKnife、Dagger、Retrofit都是基于APT(Annotation Processing Tools)实现。而编译注解核心依赖APT。当我们通过APT处理注解时,最终会将获取到的元素转换为相应的Element元素,以便获取到它们对应信息。

8、代理模式

代理模式也称委托模式,是结构型设计模式之一。是应用广泛的模式之一。
1.定义
为其他对象提供一种代理以控制对这个对象的访问。
2.使用场景
当无法或不想直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。

这里写图片描述

Android源码中的访问者模式
静态代理

书中例子:以小民诉讼的流程举例。那么需要代理律师代理,诉讼简单流程:提交申请–>进行举证–开始辩护–>诉讼完成。

诉讼接口类:

public interface ILawsuit {

    /**
     * 提交申请 
     */
    void submit();

    /**
     * 进行举证 
     */
    void burden();

    /**
     * 开始辩护
     */
    void defend();

    /**
     * 诉讼完成
     */
    void finish();
}

具体诉讼人小民:

public class XiaoMin implements ILawsuit{

    @Override
    public void submit() {
        //小民申请仲裁
        System.out.println("老板年底拖欠工资,特此申请仲裁!");
    }

    @Override
    public void burden() {
        //小民提交证据
        System.out.println("这是合同书和过去一年的银行工资流水!");
    }

    @Override
    public void defend() {
        //铁证如山
        System.out.println("证据确凿,不需要再说什么!");
    }

    @Override
    public void finish() {
        //结果
        System.out.println("诉讼成功,判决老板即日起七天内结算工资!");
    }

}

代理律师:

public class Lawyer implements ILawsuit{

    private ILawsuit mLawsuit; //持有一个具体被代理者的引用

    public Lawyer(ILawsuit lawsuit) {
        this.mLawsuit = lawsuit;
    }

    @Override
    public void submit() {
        mLawsuit.submit();
    }

    @Override
    public void burden() {
        mLawsuit.burden();
    }

    @Override
    public void defend() {
        mLawsuit.defend();
    }

    @Override
    public void finish() {
        mLawsuit.finish();
    }

}

开始仲裁:

public class Client {
    public static void main(String[] args) {
        //构造出诉讼人小民
        ILawsuit xiaomin = new XiaoMin();

        //构造一个代理律师,并将小民传递进去
        ILawsuit lawyer = new Lawyer(xiaomin);

        //律师提交申请
        lawyer.submit();

        //律师进行举证
        lawyer.burden();

        //律师代小民辩护
        lawyer.defend();

        //完成诉讼
        lawyer.finish();
    }
}

结果:

老板年底拖欠工资,特此申请仲裁!
这是合同书和过去一年的银行工资流水!
证据确凿,不需要再说什么!
诉讼成功,判决老板即日起七天内结算工资!
动态代理

Java提供了一个便捷的动态代理接口InvocationHandler,我们来实现它:

public class DynamicPorxy implements InvocationHandler{

    private Object obj; //被代理类的引用

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // 调用被代理类对象的方法
        Object result = method.invoke(obj, args);
        return result;
    }

}

这里我们通过invoke方法来调用具体的被代理方法。

修改后的Client类:

public class Client {
    public static void main(String[] args) {
        //构造出诉讼人小民
        ILawsuit xiaomin = new XiaoMin();

        //1.静态代理
        //构造一个代理律师,并将小民传递进去
        //ILawsuit lawyer = new Lawyer(xiaomin);

        //--------------------------------------
        //2.动态代理
        //构造一个动态代理
        DynamicPorxy proxy = new DynamicPorxy(xiaomin);

        //获取被代理类小民的ClassLoader
        ClassLoader loader = xiaomin.getClass().getClassLoader();

        //动态构造一个代理者律师
        ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(loader, new Class[]{ ILawsuit.class }, proxy);

        //律师提交申请
        lawyer.submit();

        //律师进行举证
        lawyer.burden();

        //律师代小民辩护
        lawyer.defend();

        //完成诉讼
        lawyer.finish();
    }
}

结果不变,由此可以看出动态代理通过一个代理类来处理N多个被代理类,其实质是对代理者与被代理者解耦。相对而言静态代理则只能为给定接口下的实现类做代理,如果接口不同那么就需要重新定义不同的代理类,较为复杂,但是静态代理更符合面向对象原则。具体使用哪种方式,根据个人喜好。

Android源码中的代理模式实现

ActivityManagerProxy代理类

ActivityManager是Android中管理和维护Activity的相关信息的类,为了隔离它与ActivityManagerService,有效降低二者的耦合,在这中间使用了ActivityManagerProxy代理类,所有对ActivityManagerService的访问都转换成对代理类的访问,这样ActivityManager就与ActivityManagerService解耦了。

9、MVC应用构架模式

MVC全称是Model - View - Controller,是模型(model)-视图(view)-控制器(controller)的缩写。MVC是一种框架模式而非设计模式,GOF把MVC看作是3种设计模式:观察者模式、策略模式与组合模式的合体,而核心是观察者模式。简而言之,框架是大智慧,用来对软件设计进行分工;设计模式是小技巧,对具体问题提出解决方案,以提高代码复用率,降低耦合度。
1.MVC的优点
(1)首先就是理解比较容易,技术含量不高,这对开发和维护来说成本较低也易于维护与修改。
(2)耦合性不高,表现层与业务层分离各司其职,对开发来说很有利。
2.MVC的缺点
(1)完全理解MVC并不是很容易。使用MVC需要精心的计划,由于它的内部原理比较复杂,所以需要花费一些时间去思考。同时由于模型和视图要严格的分离,这样也给调试应用程序带来了一定的困难。每个构件在使用之前都需要经过彻底的测试。
(2)对于小项目,MVC反而会带来更大的工作量以及复杂性。

MVC在Android中的应用

Android中对MVC的应用很经典,在android中视图View层一般采用XML文件进行界面的描述。如下例子:

<?xml version="1.0" encoding="utf-8"?>

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:id="@+id/list_item_text"
    android:textSize="16sp"
    android:gravity="left|center_vertical"
    android:padding="10dp" />

而对于模型Model部分则大多对应于本地的数据文件或网络获取的数据体,很多情况下我们对这些数据的处理也会在这一层中进行。
最后的控制器Controller则当之无愧的是右Activity承担。

10、MVP应用构架模式

在android中,业务逻辑和数据存取是紧紧耦合的,很多缺乏经验的开发者很可能会将各种各样的业务逻辑塞进某个Activity、Fragment或者自定义View中,这样会使得这些组件的单个类型臃肿不堪。如果不将具体的业务逻辑抽离出来,当UI变化时,你就需要去原来的View中抽离具体业务逻辑,这必然会很麻烦并且易出错。

MVP模式的三个角色

(1)Presenter – 交互中间人:Presenter主要作为沟通View与Model的桥梁,它从Model层检索数据后,返回给View层,使得View与Model之间没有耦合,也将业务逻辑从View角色上抽离出来。
(2)View – 用户界面:View通常是指Activity、Fragment或者某个View控件,它含有一个Presenter成员变量。通常View需要实现一个逻辑接口,将View上的操作转交给Presenter进行实现,最后,Presenter 调用View逻辑接口将结果返回给View元素。
(3)Model – 数据的存取:Model 角色主要是提供数据的存取功能。Presenter 需要通过Model层存储、获取数据,Model就像一个数据仓库。更直白的说,Model是封装了数据库DAO或者网络获取数据的角色,或者两种数据方式获取的集合。

MVP 与Activity、Fragment的生命周期

由于Presenter 经常性的持有Activity 的强引用,如果在一些请求结束之前Activity 被销毁了,那么Presenter 一直持有Activity 对象,使得Activity 对象无法回收,此时就会发生内存泄露。

那么解决方法就是采用弱引用和Activity、Fragment的生命周期来解决这个问题。首先建立一个Presenter 抽象:

public abstract class BasePresenter<T> {
    protected Reference<T> mViewRef; //View接口类型的弱引用

    public void attachView(T view){
        mViewRef = new WeakReference<T>(view); //建立关联
    }

    protected T getView(){
        return mViewRef.get(); //获取View
    }

    public boolean isViewAttached(){
        return mViewRef != null && mViewRef.get() != null; //判断是否与View建立关联
    }

    public void detachView(){
        if(mViewRef != null){
            mViewRef.clear(); //解除关联
            mViewRef = null;
        }
    }
}

通常这个View类型应该就是实现了某个特定接口的Activity或者Fragment等类型。
创建一个MVPBaseActivity基类,通过这个基类声明周期函数来控制它与Presenter 的关系。代码如下:

public abstract class MVPBaseActivity<V, T extends BasePresenter<V>> extends Activity {
     protected T mPresenter; //Presenter对象

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPresenter = createPresenter();
        mPresenter.attachView((V)this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPresenter.detachView();
    }

    protected abstract T createPresenter();
}
Android 23种设计模式全面解析 一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下: 二、设计模式的六大原则 总原则:开闭原则(. 阅读详情

相关推荐

安卓学习笔记03:安卓应用目录结构

安卓应用目录结构

howard2005的专栏 2555

Android设计模式应用举例

设计模式是在软件工程中广泛使用的解决特定问题的经过实践验证的最佳实践方法。下面是一些主流的设计模式:创建型模式:创建型模式涉及处理对象创建机制,旨在帮助在创建对象时提供更好的灵活性和复用性。这些模式包括:工厂模式、抽象工厂模式、单例模式、建造者模式和原型模式。结构型模式:结构型模式涉及处理对象之间的关系,以便更好地协作。这些模式包括:适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式和代理模式。行为型模式:行为型模式涉及处理对象之间的通信方式,以便更好地协作。

little xian的博客 1338

安卓Android应用程序开发深入实践

BroadcastReceiver是用于接收来自应用程序或者系统的广播消息的组件。系统广播是预定义好的,如电池电量变化、系统启动完成等。自定义广播是开发者在应用内部发送的广播。// 发送一个自定义的广播Android提供了大量的原生控件,如按钮(Button)、文本框(EditText)、列表视图(ListView)等,这些控件能够满足绝大多数应用的界面需求。在某些特定场景下,开发者可能需要自定义视图来满足特定的设计需求。视图的绘制通常涉及重写onDraw()

weixin_36073714的博客 1068

Android设计模式与应用场景

Android 设计模式 设计模式的目的只有一个,降低对象之间的耦合,增强程序的复用性、拓展性、维护性 1.设计模式的分类 设计模式一般分为三类:创建型模式、结构型模式、行为型模式 1.1 创建型模式(5种) (口诀:单抽工建原) 用来创建对象的。一共有五种:单例模式、原型模式、建造者模式、工厂方法模式、抽象工厂模式、。 [单例模式] : 确保某一个类只有一个实例,并且提供一个全局访问点。 [抽象工厂模式]: 创建多个产品族中的产品对象。 [工厂方法模式]: 定义:让子类来决定要创建哪个对象;适用于

Alien__Chao的博客 3899

Android-DesignPatterns:23种设计模式在Androd项目中的代码实践,根据实际的需求功能场景合理使用对应的设计模式

设计模式在Andorid中的实践 23种设计模式在Androd项目中的代码实践,根据实际的需求功能场景合理使用对应的设计模式。 让代码遵循七大原则(单一职责原则,开闭原则,里氏代换原则,依赖倒转原则,接口隔离原则,迪米特法则,合成/聚合替代原则) 使代码增加可重用性,可维护性,让代码更容易被他人理解,保证代码可靠性。 持续更新。

设计模式在android中的应用之1,简单工厂模式

简单工厂模式在android中的应用。简单工厂模式相信大家都懂了。但是我觉得理论知识缺乏应用永远显得苍白无力。于是贴出了这一系列代码。都是关于设计模式在android中的简单应用。

Android 常用设计模式和实例

设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

Android 领域开发程序员,希望通过写博客的方式不断的总结提升自己,大家共同进步哦! 2114

android常用设计模式

android的设计模式文档,里面详细解释了常用的8种设计模式

java 注册机制的实现_note/关于java中的回调机制和注册实现.md at master · hellmonky/note · GitHub...

关于java中回调机制和注册的实现:在实现多种接口的具体实现和interface的接口调用的过程中,随着代码的编写,想实现类似于Spring中注册机制,Spring基于的IOC是其核心。本文分析java的接口回调机制细节,然后结合Spring的IoC原理进行思考。一 java中的接口回调机制1.1 回调的概念:模块之间都存在一定的调用关系,从调用方式上看,可以分为三类:同步调用、异步调用和回调。同...

weixin_34997593的博客 660

Python 爬取新浪财经 7x24(1): 下载数据

前言 最近在做一个需要很多财经数据的项目。于是想到可不可以通过爬虫来解决(尝试白嫖)。 提供财经数据的网站有很多个,其中比较靠谱和更新比较及时的应该是新浪7x24 live数据。 http://finance.sina.com.cn/7x24/?tag=0 这个问题有一定的难度,因为这个网页是动态加载的。每一次只会加载部分数据,而只有拉到底部才可以加载新的数据。 于是乎,我们要做的事情是: 下载数据 保存到数据库 本篇介绍如何下载数据。 代码 闲言少叙书归正文,代码的实现如下: import reque

ZJ_11701的博客 2905

【python3.7】解决报错 error: Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft C++

解决pip安装py7zr遇到的报错问题。

水w的博客 3942

android设计模式的应用场景,瞬间高大上了

如果你觉得这些内容对你有帮助,可以扫码领取!!!!最后为了帮助大家深刻理解。

2301_76278775的博客 791

Unity - gamma space下还原linear space效果

还有头发之后的 (头发没有处理完整,因为使用 ASE 连连看练出来的,使用 surface shader,虽然可以生成一下 vert, frag 的方式在修改,但是我懒得去修改了,这样就是 PBR 的 BRDF 里面的部分曲线是不一样的,所以可以看到头发有一些差异)其实上面的代码判断 是否有分量 > 1.0f 的方式来判断是否 HDR 是不太合理的,因为不同的贴图格式的编码方式不同。还有比较隐蔽的一些颜色相关的常量值 (比如PBR中的 绝缘体的 F0 常量值,等等)

Jave.Lin 的学习笔记 2830

安卓Android 架构模式及UI布局设计

界面设计与程序逻辑分离:有利于并行安卓中的架构模式 **优势:** 1. 设计可扩展的应用程序,方便进行未来的更改和更新。 2. 实现模块化设计,提高代码质量,便于测试和维护。开发,后期修改界面时不需修改程序逻辑代码。设计模式MVC、MVP、MVVM

m0_74154295的博客 3918

别再写XPath改DOM了!用OpenClaw零代码搞定爬虫全流程(抓取+清洗+存储)

免费版的大模型调用次数有限制(每天100次),但企业版是无限的,还能私有化部署;大模型分析DOM结构有时候会慢1-2秒,但比起节省的时间,完全可以接受;自定义Skill的文档还不够完善,但社区很活跃,有问题在Discord里问,很快就能得到回复。但总的来说,OpenClaw真的改变了我写爬虫的方式——以前我是“代码的奴隶”,现在我是“需求的提出者”,把时间花在更有价值的业务逻辑上,而不是重复繁琐的DOM调试上。如果你也在被传统爬虫折磨,强烈建议你试试OpenClaw,相信我,用了就回不去了。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1314

Vue3 - 详细实现流程图编辑器可视化平台示例代码,打造前端web网页流程图在线编辑绘制操作展示,vue3自定义绘制流程图在页面上画流程图功能(提供各种操作按钮及节点控件,界面美观交互式流程图插件)

vue3,绘制流程图,在线流程图制作,在vue3中实现流程图,vue3做一个制作流程图的功能,vue3流程图组件,vue3流程图,流程图绘制展示,vue3流程图可视化在线编辑源码,基于VUE3的在线绘制流程图工具,vue3+logicflow流程图,绘制动态流程图并自定义节点和线,vue使用logicFlow绘制流程图,生成各种流程图图形可连接点移除,基于Vue的流程图组件,工作流程图,流程编辑器,vue3流程组件,vue-flow绘制流程图,绘制流程图示例demo,vue3 logicflow流程图使用教

🏆 前端领域优质创作者 9967

安卓开发用到的设计模式(2)结构型模式

本文介绍了安卓开发中常用的五种结构型设计模式:适配器模式(用于RecyclerView和网络请求适配)、装饰器模式(扩展Context功能与View装饰)、代理模式(管理图片加载和权限检查)、桥接模式(实现主题切换和数据存储分离)以及组合模式(构建View树结构和菜单层级)。这些模式通过解耦接口与实现、复用对象结构等方式,有效提升了代码的可维护性和扩展性,是安卓开发中的核心架构思想。

分享Android应用和系统开发、音视频编码、性能优化相关知识 1213

Istio ICA考试之路---2-2

找到dr部分,这部分可以在mirroring里找也可以和题2-1一样在Traffic Management的dr里复制,内容都一样。此题之后都是在cluster-2上操作,所以就不需要再切换了.之后的几题2.1节就忽略掉了。可以看到,80%的流量被镜像到了dev上,实际考试这步可以忽略。看到ex-ip是192.168.126.220。获取gw,把gateways加入到vs配置中。获取istio-ingress的ex-ip。就获得了这样一个模板文件。查看2个pod的日志。

Q先生 854

【Android设计模式应用】 谈谈Android中的单例模式

以上都是同学我结合网上资料进行整理的单例模式的分析总结,简单来说,单例模式在设计模式中是非常常见的,它简单但同时又简单,值得我们继续深入探讨下去, 下面我简单总结一下单例模式一个核心原理就是私有构造,并且通过静态方法获取一个实例。自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。

2401_84048034的博客 968

泛微OA自定义post接口和路径(无侵入)

泛微OA自定义post接口和路径(无侵入)

技术分享 3870

《YOLO26/YOLO11/YOLOv8改进与系统实战》,改进与系统实战专栏目录和介绍

YOLOv8 是目前比较火和比较成熟的深度学习框架,是2023年1月发布的,由 Ultralytics 团队开发。Ultralytics自YOLOv5 开始一直积极维护和更新 YOLO 框架,因此 YOLOv8 也享有持续的维护与升级支持。因此我写下《手把手教你YOLOv8实战》专栏,专门为那些对计算机视觉、深度学习、以及目标检测技术感兴趣的读者设计。通过本专栏,你将深入理解 YOLOv8 的核心原理与实际应用,从0 开始学习并掌握如何使用 YOLOv8 完成各类目标检测任务,帮助你快速上手并掌握 YOLO

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1万+

Android中的设计模式

中所提到的,总共有 23 种设计模式。这些模式可以分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、行为型模式(Behavioral Patterns)。当然,我们还会讨论另一类设计模式:J2EE 设计模式。根据设计模式的参考书。

lhm1124的博客 1143

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Android ClassyShark 中的空对象模式:EmptyFullArchiveReader 设计解析与实战应用

Android ClassyShark 是一款强大的 Android 和 Java 字节码查看器,它能够深入分析 APK 文件、JAR 包和 DEX 文件,为开发者提供清晰的代码结构和依赖关系视图。在 ClassyShark 的核心架构中,**空对象模式(Null Object Pattern)** 被巧妙地应用于 `EmptyFullArchiveReader` 类,这是一种优雅的设计模式,用于

gitblog_01100的博客 1041

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Android中的单例模式(java单例模式详解,Glide,EventBus,LayoutInfalter的源码单例模式详解)

名称优点缺点普通的单例模式实现简单,操作简单,理解简单多线程并发操作资源的时候不安全,会导致资源数据混乱饿汉模式线程安全内存资源的消耗会相对多一些懒汉模式线程安全需要上锁,线程资源需要同步排队等待执行,性能方面相对较低静态内部类模式线程安全、避免了对象的实例化操作,可通过外部类直接访问静态的内部类操作创建单一的实例对象。暂无。

weixin_46039528的博客 5503

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Android中的Doze模式

概述 Android 6.0引入的Doze机制在于节省系统耗电量,保护电池,延长电池的使用时间。当设备未连接至电源,且长时间处于闲置状态时,系统会将应用进入Doze,置于App Standby模式。而最终的效果,能提升30%的电量续航能力。 Doze模式的状态 该状态与API版本无关,未适配API23以上的应用只要运行在6.0以上的系统上就会受到Doze模式的影响。 在屏幕熄灭30分钟、没有晃动并且在不充电的时候,会进入Doze模式 在进入Doze模式后,每间隔一段时间,会进入一段时长为30s的m

zwylovemzj的博客 5064

【设计模式】模板方法模式 在java中的应用

【设计模式】模板方法模式 在java中的应用

qq_42320804的博客 1445
上一篇: android Java多线程的使用解析
下一篇: android 使用ffmpeg音视频播放(一)
trinity2018
博客等级 码龄14年 3粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值