Android面试Java基础篇(五)

2021-03-25  本文已影响0人  肖义熙
问:简单讲讲你经常见到使用到的一些设计模式

答:设计模式有六大原则,分别为:
1. 单一职责原则: 每个类的职责单一,易于维护,可扩展性高,降低变更引起的风险
2. 开放封闭原则: 一个模块、类、函数应当是对修改关闭,扩展开放
3. 里氏替换原则: 使用父类的地方能够使用子类来替换,反过来,则不行。
4. 接口隔离原则: 一个类对另一个类的依赖应该建立在最小的接口上。
5. 依赖倒置原则: 抽象不应该依赖于细节,细节应当依赖于抽象。
6. 迪米特法则: 一个类尽量不要与其他类发生关系

Android中经常使用的设计模式 单例模式、建造者模式(Builder)、工厂方法模式、观察者模式、迭代器模式、代理/委托模式、适配器模式、装饰者模式、享元模式 等等

1. 单例模式: 单例模式包含有几种实现:懒汉式(线程不安全)、饿汉式、加锁懒汉式(线程安全)、双重校验锁、静态内部类、枚举类等

  //(1)懒汉式(线程不安全)----延迟初始化,不浪费内存,但线程不安全。
  public class Singleton{
    //私有化构造方法,防止外部直接new
    private Singleton(){
    }
    private static Singleton instance = null;
    
    public static Singleton getInstance(){
      if(instance == null){
        instance = new Singleton();
      }
      return instance;
    }
  }
  //(1)饿汉式(线程安全)----不能延迟初始化,如果未使用浪费内存,线程安全
  public class Singleton{
    //私有化构造方法,防止外部直接new
    private Singleton(){
    }
    private static Singleton instance = new Singleton();
    
    public static Singleton getInstance(){
      return instance;
    }
  }
  //(1)加锁懒汉式(线程安全)----能延迟初始化且线程安全,但是加锁效率低
  public class Singleton{
    //私有化构造方法,防止外部直接new
    private Singleton(){
    }
    private static Singleton instance = null;
    
    public static synchronized Singleton getInstance(){
      if(instance == null){
        instance = new Singleton();
      }
      return instance;
    }
  }
  //(1)双重检验锁 ----能延迟初始化且线程安全,第一次初始化时效率低,之后再使用效率高
  public class Singleton{
    //私有化构造方法,防止外部直接new
    private Singleton(){
    }
    private static Singleton instance = null;
    
    public static Singleton getInstance(){
      if(instance == null){
        synchronized(Singleton.class){
          if(instance == null){
             instance = new Singleton();
          }
        }
      }
      return instance;
    }
  }
  //(1)静态内部类 ----延迟初始化,且线程安全,效率还比较高
  public class Singleton{
    //私有化构造方法,防止外部直接new
    private Singleton(){
    }
    private static Singleton instance = null;
     public static Singleton getInstance() {
        //第一次调用getInstance方法时才加载SingletonHolder并初始化sInstance
        return SingletonHolder.sInstance;
      }
    
      //静态内部类
      private static class SingletonHolder {
        private static final Singleton sInstance = new Singleton();
      }
  }
  //(1)枚举类 ----线程安全,写法简单,但可读性差,枚举常量比静态常量费内存。
  public enum Singleton {

    INSTANCE;   //定义一个枚举的元素,它就是Singleton的一个实例

    public void doSomething() {
    }
  }  

2. 建造者模式: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。Android中最为常见的如:AlertDialog.Builder、 OkHttp、Retrofit等

  //AlertDialog.Builder 的使用 
  AlertDialog.Builder builder = new AlertDialog.Builder(activity);//创建一个Builder对象
  builder.setIcon(R.drawable.icon);
  builder.setTitle("标题");
  builder.setMessage("信息");
  builder.setPositiveButton("确定",
        new DialogInterface.OnClickListener() {
              @Override
              public void onClick(DialogInterface dialog, int which) {

              }
        });
  AlertDialog alertDialog = builder.create();//创建AlertDialog对象
  alertDialog.show();//展示AlertDialog
        //OkHttp的创建
        OkHttpClient mOkHttpClient = new OkHttpClient.Builder()
                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(DEFAULT_TIMEOUT,TimeUnit.SECONDS)
                .addInterceptor(interceptor)
                .build();
        String baseUrl = IPUtils.BASE;
        //Retrofit的创建
        Retrofit mRetrofit = new Retrofit.Builder()
                .client(mOkHttpClient)
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create(buildGson()))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        ApiService api = mRetrofit.create(ApiService.class);

3. 工厂方法模式: 定义一个用于创建对象的接口,让子类决定实例化哪个类。Android中经常使用的例如:线程池ThreadPoolExecutor构造方法中用于生成线程的参数ThreadFactory、用于生成Bitmap的BitmapFactory等 。工厂方法遵循了 里氏替换原则

  //工厂方法介绍及使用:
//1.动物抽象类,定义了一个吃食物的标准接口
interface Animal{
  void eat();
}
//2.实际的动物,继承动物抽象类,实现eat方法
class Dog implements Animal{
  @Override
  void eat(){
    System.out.println("狗吃东西")
  }
}
class Catimplements Animal{
  @Override
  void eat(){
    System.out.println("猫吃东西")
  }
}

//3. 构造一个工厂,返回接口类型(实际的动物)
public class Factory {
    public static Animal decodeDog(){
        return new Dog();
    }

    public static Animal decodeCat(){
        return new Cat();
    }
}
public static void main(String[] args){
  //使用
  Animal dog = Factory.decodeDog();   //产生一个狗产品
  dog.eat();    //输出:狗吃东西
  Animal cat = Factory.decodeCat();  //产生一个猫产品
  cat.eat();    //输出:猫吃东西
}

4. 观察者模式: 定义对象间的一种一对多的依赖关系,当一个对象的状态发送改变时,所依赖于它的对象都得到通知并被自动更新。Android中最为常见的RxJava、MVVM模式中最为重要的思想我认为就是观察者模式,如:Jetpack中的Lifecycle、LiveData。观察者模式遵循了 依赖倒置原则

//观察者在Jetpack的Lifecycle中的使用 
public class LifecycleTestActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.xxx);
        //Lifecycle 生命周期,  MyObserver为观察者实现了LifecycleObserver ,被观察者其实是getLifecycle()获取的Lifecycle
        getLifecycle().addObserver(new MyObserver());
    }
    @Override
    protected void onResume() {
        super.onResume();
        Log.i("tag", "onResume: ");
    }
}

public class MyObserver implements LifecycleObserver {
    
    @OnLifecycleEvent(value = Lifecycle.Event.ON_RESUME)
    public void connect(){
        //观察者观察到Activity的生命周期变化为 onResume时得到执行
        Log.i("tag", "connect: ");
    }
}

5. 迭代器模式: 提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。迭代器(Iterator)模式,又叫做游标(Cursor)模式,Android中常见的迭代器模式实现如:数据库,ContentProvider返回的Cursor对象,List,Map等集合。遵循了 单一职责原则

//1、创建迭代器接口
public interface Iterator {
    boolean hasNext();    //是否存在下一条记录
    Object next();        //返回当前记录并移到下一条记录
}

//2、创建容器接口
public interface Aggregate {
     int size();//容器大小
     String get(int location);//获取获取中指定位置的号码
     void add(String tel);//添加号码到容器中
     void remove(String tel);//从容器中移除号码
     Iterator iterator();//返回容器的迭代器
}

//3、创建具体迭代器类
public class DeliveryIterator implements Iterator {
    private Aggregate aggregate;//容器对象
    private int index;//当前索引
    public DeliveryIterator(Aggregate aggregate) {
         this.aggregate = aggregate;//初始化容器对象
    }
    @Override
    public boolean hasNext() {//是否存在下一条记录
        if (index < aggregate.size()) {
            return true;
        } else {
            return false;
        }
    }
    @Override
    public Object next() {//返回当前记录并移到下一条记录
        return aggregate.get(index++);
    }
}

//4、创建具体容器类
public class DeliveryAggregate implements Aggregate {
    private List<String> list = new ArrayList<>();//内部使用list来存储数据
    public int size() {//容器大小
        return list.size();
    }
    public String get(int location) {
        return list.get(location);
    }
    public void add(String tel) {
        list.add(tel);
    }

    public void remove(String tel) {
        list.remove(tel);
    }
    @Override
    public Iterator iterator() {////返回迭代器
        return new DeliveryIterator(this);
    }
}

    //使用 
    public void test() {
        Aggregate aggregate=new DeliveryAggregate();    //获取容器对象
        aggregate.add("1111");
        aggregate.add("2222");
        aggregate.add("3333");
        aggregate.add("9527");
        //迭代容器获取值
        Iterator iterator = aggregate.iterator();
        while (iterator.hasNext()){
            String tel = (String) iterator.next();
        }
    }

6. 代理/委托模式: 为其他对象提供一种代理以控制这个对象的访问。在平常使用Retrofit中Retrofit.create(xxxService)中就是使用的 代理模式(动态代理)
静态代理:在代码编译时就已经生成,委托类和代理类实现共同的接口。

//1.委托对象和代理对象的共同接口
public interface Subject{
  void request();
}

//2.委托类的时实现
public class RealSubject implements Subject{
  @Override
  void request(){
    System.out.print("委托类的实现")
  }
}

//代理类的实现
public class SubjectProxy implements Subject{
  Subject subject;
  public SubjectProxy(){
    subject = new RealSubject();
  }
  @Override
  void request(){
    subject.request();
  }
}

//静态代理的使用
public class ProxyTest {
    public static void main(String[] args) {
        //静态代理
        SubjectProxy proxy = new SubjectProxy();
        //通过代理访问
        proxy.request();
     }
}

动态代理:在运行时才会生成代理类,通过ClassLoader加载到JVM中。代理类需要实现 Invocationhandler接口。

//1、2和静态代理一样,第三部需要继承InvocationHandler接口
public class ProxyHandler implements InvocationHandler{
  private Subject subject;
  public ProxyHandler(){
    subject = new RealSubject();
  }
  //实现InvocationHandler接口的invoke()方法 
  @Overide
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
    Object object = method.invoke(subject, args);
    return object;
  }
}

//使用
public static void main(String[] args) {
      ProxyHandler handler = new ProxyHandler();
      Subject proxy = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), handler);
      proxy.request();
}

7. 适配器模式: 将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。rv.setAdapter() 在Android中RecyclerView的Adapter就是使用的适配器模式。遵循封闭开放原则,只是对一个无法使用的类进行扩展,使得可以使用

看看自己的RecyclerView的setAdapter

8. 装饰者模式: 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。可以说是类似继承的一种实现。被装饰者可以不知道装饰者的存在,同时新增功能时原有代码也无需改变,符合开放封闭原则。 其实在Android中,Activity、Service、Application等都是一个Context,实际上都是Context的装饰者,Context中有一个startActivity() Context的实现类为ContextImpl, ContextWrapper其实就是抽象装饰角色,Service和Activity又继承了ContextWrapper,

//1.创建抽象组件
public abstract class Animal(){
  public abstract void eat();
}
//2.创建具体组件(实现抽象组件)
public class People extends Animal(){
  @Overried
  public void eat(){
    System.out.print("人会吃饭")
  }
}

//创建抽象装饰角色
public abstract class AnimalDecorator extends Animal{    //继承Animal,与父类拥有相同的方法
  private Animal animal;
  public AnimalDecorator(Animal animal){
    this.animal = animal;
  }
  @Overried
  public void eat(){
    animal.eat();
  }
}

//创建具体装饰者类 
public class MyPeople extends AnimalDecorator{
  public MyPeople(Animal animal){
    super(animal)
  }
  public void eat(){
    super.eat();
    sleep();
  }

  private void sleep(){
    System.out.print("我还会睡觉");
  }
}

//使用 
public void test(){
  Animal animal = new People();
  AnimalDecorator ad = new MyPeople(animal);
  ad.eat();  //输出“人会吃饭” “我还会睡觉”
}

9. 享元模式: 使用共享对象可有效地支持大量的细粒度的对象。例如:String常量池的概念。

上一篇下一篇

猜你喜欢

热点阅读