Android 设计模式相关面试题

单例

单例介绍

  • 单例的概念

    单例模式是一种对象创建模式,它用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。

  • 单例的好处

    1. 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销。
    2. 由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。

单例的六种写法和各自的特点

  1. 饿汉

    • code

      public class HungrySingleton {
      private static final HungrySingleton sHungrySingleton = new HungrySingleton();
      
      public HungrySingleton() {
      }
      
      public static HungrySingleton getHungrySingleton() {
          return sHungrySingleton;
      }
      }
    • 不足之处
      无法对instance实例做延时加载

  2. 懒汉
    • code

      public class LazySingleton {
      private static LazySingleton instance;
      public LazySingleton() {
      }
      public static LazySingleton getInstance(){
      //第一次调用的时候会初始化
      if (instance==null){
      instance=new LazySingleton();
      }
      return instance;
      }
      }
    • 不足之处
      在多线程并发下这样的实现是无法保证实例的唯一的
  3. 懒汉线程安全

    • code

      public class LazySafetySingleton {
      private static LazySafetySingleton instance;
      
      public LazySafetySingleton() {
      }
      
      //方法中声明synchronized关键字
      public static synchronized LazySafetySingleton getInstance() {
          if (instance == null) {
              instance = new LazySafetySingleton();
          }
          return instance;
      }
      
      //同步代码块实现
      public static LazySafetySingleton getInstance() {
          synchronized (LazySafetySingleton.class) {
              if (instance == null) {
                  instance = new LazySafetySingleton();
              }
          }
          return instance;
      }
      }
    • 不足之处 性能

  4. DCL(双重检查锁机制)

    • code

      public class DclSingleton {
      private static volatile DclSingleton mInstance = null;
      //    private static DclSingleton mInstance = null;
      private DclSingleton() {
      
      }
      public static DclSingleton getInstance() {
          //避免不必要的同步
          if (mInstance == null) {
              //同步
              synchronized (DclSingleton.class) {
                  if (mInstance == null) {
                      mInstance = new DclSingleton();
                  }
              }
          }
          return mInstance;
      }
      }
    • 不足之处
      JVM的即时编译器中存在指令重排序的优化

  5. 静态内部类

    • code

      public class StaticInnerSingleton {
      private StaticInnerSingleton() {
      
      }
      public StaticInnerSingleton getInstance() {
          return SingletonHolder.sInstance;
      }
      /**
       * 类级的内部类,也就是静态类的成员式内部类,该内部类的实例与外部类的实例
       * 没有绑定关系,而且只有被调用时才会装载,从而实现了延迟加载
       */
      private static class SingletonHolder {
      /**
      * 静态初始化器,由JVM来保证线程安全
      */
          private static final StaticInnerSingleton sInstance = new StaticInnerSingleton();
      }
      }
    • 优点 JVM本身机制保证了线程安全 没有性能缺陷

    • 原因 static/final
  6. 枚举

    • code

      public enum  EnumSingleton {
      //定义一个枚举的元素,它就是Singleton的一个实例
      INSTANCE;
      }
    • 优点 写法简单 线程安全

    总结

    • 饿汉:无法对instance实例进行延迟加载
    • 懒汉:多线程并发情况下无法保证实例的唯一性
    • 懒汉线程安全:使用synchronized导致性能缺陷
    • DCL:JVM即时编译器的指令重排序
    • 静态内部类/枚举:延迟加载/线程安全/性能优势

Android 中的单例

1. Application
    public class MyApplication extends Application {

    public static MyApplication instance;

    @Override
    public void onCreate() {
        super.onCreate();
        //设置 Logger.init(TAG).logLevel(LogLevel.NONE) 可以设置为不打印日志
        PosHelper.getPosApi().initSDK(this);
        instance = this;
    }

    public static MyApplication getInstance() {
        return instance;
    }

}
2. 单例模式引起的内存泄露
3. EventBus的坑

Builder模式

Java 的 Builder 模式

  1. 概念

    建造者模式是较为复杂的创建型模式,它将客户端与包含多个组成部分(或部件)的复杂对象的创建过程分离

  2. 使用场景
    Glide Okhttp
    当构建一个对象需要很多参数的时候,并且参数的个数或者类型不固定的时候

  3. UML结构图分析
  4. 实际代码分析

    public class Product {
    private String partA;//定义部件,部件可以是任意类型,包括值类型和引用类型
    private String partB;
    private String partC;
    
    public String getPartA() {
        return partA;
    }
    
    public void setPartA(String partA) {
        this.partA = partA;
    }
    
    public String getPartB() {
        return partB;
    }
    
    public void setPartB(String partB) {
        this.partB = partB;
    }
    
    public String getPartC() {
        return partC;
    }
    
    public void setPartC(String partC) {
        this.partC = partC;
    }
    }
    abstract class Builder {
    //创建产品对象
    protected Product mProduct = new Product();
    
    public abstract void buildPartA();
    
    public abstract void buildPartB();
    
    public abstract void buildPartC();
    
    // 返回产品对象
    public Product getResult() {
        return mProduct;
    }
    }
    public class ConcreteBuilder extends Builder {
    @Override
    public void buildPartA() {
    
    }
    
    @Override
    public void buildPartB() {
    
    }
    
    @Override
    public void buildPartC() {
    
    }
    }
    public class Director {
    private Builder mBuilder;
    
    public Director(Builder builder) {
        mBuilder = builder;
    }
    
    public void setBuilder(Builder builder) {
        this.mBuilder = builder;
    }
    
    //产品构建与组装方法
    public Product construct() {
        mBuilder.buildPartA();
        mBuilder.buildPartB();
        mBuilder.buildPartC();
        return mBuilder.getResult();
    }
    }
  5. Builder模式的优点

    • 松散耦合:生产器模式可以用同一个构建算法构建出表现不同的产品,实现产品构建和产品表现上的分离
    • 可以很容易的改变产品的内部表示
    • 更好的复用性:生产器模式很好的实现构建算法和具体产品实现的分离
  6. Builder模式的缺点

    • 会产生多余的 Builder 对象以及 Director 对象消耗内存
    • 对象的构建过程暴露

总结

  • Builder:它为创建一个产品 Product 对象的各个部件指定抽象接口
  • ConcreteBuilder:它实现了 Builder 接口,实现各个部件的具体构造和装配方法
  • Product:它是被构建的负责对象,包含多个组成部件
  • Director:指挥者又称导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系

Builder 模式在 Android 中的应用

  1. AlertDialog
  2. Glide/ OkHttp

Adapter适配器模式

Adapter模式详解

  1. 适配器模式定义

    将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以在一起工作,其别名为包装器(Wrapper)

  2. 类适配器

    • 类适配器定义

      类的适配器模式把适配的类的API转换为目标类的API

    • UML结构图解释

    • code详解

      public class Adaptee {
      public void sampleOperation1() {
      
      }
      }
      public interface Target {
      void sampleOperation1();
      
      void sampleOperation2();
      }
      public class Adapter extends Adaptee implements Target {
      @Override
      public void sampleOperation2() {
      
      }
      }
    • 总结

      1. 类适配器使用对象集成的方式,是静态的定义方式
      2. 对于类适配器,适配器可以重定义Adaptee的部分行为
      3. 对于类适配器,仅仅引入了一个对象,并不需要额外的引用来间接得到Adaptee
      4. 对于类适配器,由于适配器直接集成了Adaptee,使得适配器不能和Adaptee的子类一起工作
  3. 对象适配器

    • 对象适配器定义

      与类的适配器模式一样,对象的适配器模式把被适配的类的API转换为目标类的API,与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类

    • UML结构图解释

    • code详解

      public class Adaptee {
      public void sampleOperation1() {
      
      }
      }
      public interface Target {
      void sampleOperation1();
      
      void sampleOperation2();
      }
      public class Adapter implements Target {
      private Adaptee mAdaptee;
      
      public Adapter(Adaptee adaptee) {
          mAdaptee = adaptee;
      }
      
      @Override
      public void sampleOperation1() {
          mAdaptee.sampleOperation1();
      }
      
      @Override
      public void sampleOperation2() {
      
      }
      }
    • 总结

      1. 对象适配器使用对象组合的方式,是动态组合的方式
      2. 对于对象适配器而言,一个适配器可以把多种不同的源适配到同一个目标
      3. 对于对象适配器,要重定义Adaptee的行为比较困难
      4. 对于对象适配器,需要额外的引用来间接得到Adaptee

Adapter模式在Android中的实际应用

Listview

  1. UI

    • Listview 的布局是由一条一条的 Item 组成的,这每一个 Item 又是一个 View。通过 Adapter 适配器这个桥梁将 View 添加到 ListView 中。

    • 一个 Adapter 是 AdapterView 视图与数据之间的桥梁,Adapter 提供数据的访问,也负责为每一项数据产生一个对应的 View。
    • 每一项数据产生对应的 View 之后,然后将 View 添加到ListView之中。
    • MVC
  2. 源码

装饰模式

装饰模式详解

  1. 概念

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

  2. 使用场景

    • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
    • 当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式。
  3. UML结构图分析
  4. 实际代码分析
interface Component {
    public void operation();
}
public class Decorator implements Component {
    private Component mComponent;//维持一个对抽象构建对象的引用

    public Decorator(Component component) {//注入一个抽象构建类型的对象
        mComponent = component;
    }

    @Override
    public void operation() {
        mComponent.operation();//调用原有业务方法
    }
}
public class ConcreteDecorator extends Decorator {

    public ConcreteDecorator(Component component) {
        super(component);
    }

    public void operation() {
        super.operation();//调用原有业务方法
        addedBehavior();//调用新增业务方法

    }

    //新增业务方法
    public void addedBehavior() {

    }
}

5 . 装饰模式的优点

*  对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加。
*  可以通过一种动态的方式来扩展一个对象的功能。
*  可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合。 

装饰模式在 Android 的实际应用

  1. Context 类簇在装饰模式的运用

外观模式

外观模式详解

  1. 概念

    外观模式的主要目的在于让外部减少与子系统内部多个模块的交互,从而让外部能够更简单的使用子系统。它负责把客户端的请求转发给子系统内部的各个模块进行处理。

  2. 使用场景

    • 当要为一个复杂子系统提供一个简单接口时。
    • 客户程序与抽象类的实现部分 之间存在着很大的依赖性。
    • 当需要构建一个层次结构的子系统时。
  3. UML结构图分析
  4. 实际代码分析
public class ModuleA {
    public void testFuncA() {

    }
}
public class ModuleB {
    public void testFuncB() {

    }
}
public class ModuleC {
    public void testFuncC() {

    }
}
public class Facade {
    private ModuleA mModuleA = null;
    private ModuleB mModuleB = null;
    private ModuleC mModuleC = null;
    private static Facade sInstance = null;

    private Facade() {
        mModuleA = new ModuleA();
        mModuleB = new ModuleB();
        mModuleC = new ModuleC();
    }

    public static Facade getInstance() {
        if (sInstance == null) {
            sInstance = new Facade();
        }
        return sInstance;
    }

    public void testOperation() {
        mModuleA.testFuncA();
        mModuleB.testFuncB();
        mModuleC.testFuncC();
    }
}
public class Client {
    public Client() {
        Facade.getInstance().testOperation();
    }

}
  1. 外观模式的优点
    • 由于Facade 类封装了各个模块交互的过程,如果今后内部模块调用关系发生了变化,只需要改变 Facade 实现就可以了。
    • Facade 实现是可以被多个客户端调用的。

外观模式在 Android 中的实际运用

  1. ContextImpl —>Android 中的外观类

组合模式

组合模式详解

  1. 概念

    将对象以树形结构组织起来,以达成“部分—整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。

  2. 使用场景

    • 需要表示一个对象整体或部分层次
    • 让客户端能够忽略不同对象层次的变化
  3. UML结构图分析
  4. 实际代码分析

    public abstract class File {
    private String name;
    
    public File(String name) {
        this.name = name;
    }
    
    //操作方法
    public void setName(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
    
    public abstract void watch();
    
    //组合方法
    public void add(File file) {
        throw new UnsupportedOperationException();
    }
    
    public void remove(File file) {
        throw new UnsupportedOperationException();
    }
    
    public void getChild(int position) {
        throw new UnsupportedOperationException();
    }
    }
    public class Folder extends File {
    private List mFileList;
    
    public Folder(String name) {
        super(name);
        mFileList = new ArrayList<>();
    }
    
    @Override
    public void watch() {
        StringBuffer fileName = new StringBuffer();
        for (File file : mFileList) {
            fileName.append(file.getName() + ":");
        }
    }
    
    @Override
    public void add(File file) {
        mFileList.add(file);
    }
    
    @Override
    public void remove(File file) {
        mFileList.remove(file);
    }
    
    @Override
    public void getChild(int position) {
        mFileList.get(position);
    }
    }
    public class TextFile extends File {
    public TextFile(String name) {
        super(name);
    }
    
    @Override
    public void watch() {
    
    }
    }
    public class testComposite {
    public testComposite() {
        TextFile textFileA=new TextFile("a.txt");
        TextFile textFileB=new TextFile("b.txt");
        TextFile textFileC=new TextFile("c.txt");
        textFileA.watch();
        Folder folder=new Folder("学习资料");
        folder.add(textFileA);
        folder.add(textFileB);
        folder.add(textFileC);
        folder.watch();
    }
    }
  5. 组合模式的优点
    • 高层模块调用简单
    • 节点自由增加

组合模式在 Android 中的实际运用

  1. Android 中View的结构是树形结构
  2. ViewGroup 源码分析 抽象类 实现ViewManager ViewParent 接口

策略模式

策略模式详解

  1. 概念

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

  2. 使用场景

    • 一个类定义了多种行为,并且这些行为在这个类的方法中以多个条件语句的形式出现,那么可以使用策略模式避免在类中使用大量的条件语句。
  3. UML结构图分析
  4. 实际代码分析

    public class Context {
    private AbstractStrategy mAbstractStrategy;
    
    public void setAbstractStrategy(AbstractStrategy abstractStrategy) {
        this.mAbstractStrategy = abstractStrategy;
    }
    
    public int calclatePrice(int km) {
        return mAbstractStrategy.calculatePrice(km);
    }
    }
    public interface AbstractStrategy {
    //按距离来计算价格
    int calculatePrice(int km);
    }
  5. 策略模式的优点
    • 上下文(Context)和具体策略 (ConcreteStrategy )是松耦合关系。
    • 策略模式满足“开-闭原则”。

策略模式在 Android 中的实际应用

  1. Volley 中对于HttpStack 的设计用到的就是策略模式
  2. 动画中的时间插值器

模板方法

模板方法详解

  1. 概念

    模板方法是通过定义一个算法架构,而将算法中的步骤延迟到子类,这样子类就可以复写这些步骤的实现来实现特定的算法。

  2. 使用场景

    • 多个子类有公共的方法,并且逻辑基本相同。
    • 重要、复杂的算法,可以把核心算法设计为模板方法
    • 重构时,模板方法模式是一个经常使用的模式
  3. UML结果图分析
  4. 实际代码分析

    public abstract class AbstractWork {
    protected void getUp() {
    
    }
    
    protected abstract void gotoWork();
    
    protected abstract void work();
    
    protected abstract void goOffWork();
    
    //TemplateMethod,大家都有共同的方法步骤
    public final void newDay() {
        getUp();
        gotoWork();
        work();
        goOffWork();
    }
    }
    public class BossWork extends AbstractWork {
    @Override
    protected void gotoWork() {
    
    }
    
    @Override
    protected void work() {
    
    }
    
    @Override
    protected void goOffWork() {
    
    }
    }
    ublic class StaffWork extends AbstractWork {
    @Override
    protected void gotoWork() {
    
    }
    
    @Override
    protected void work() {
    
    }
    
    @Override
    protected void goOffWork() {
    
    }
    }

模板方法模式在 Android 中的实际应用

你可能感兴趣的:(Android面试)