Android面试系列之【设计模式】

简介

设计模式(Design Pattern)
设计模式是什么?它是一套理论,由前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。“道可道,非常道”非常适合描述设计模式。

不得不说的六大设计原则

  • 单一职责原则:要求我们实现类要职责单一
  • 里氏替换原则:要求我们不要破坏继承关系体系
  • 依赖倒置原则:要求我们要面向接口编程
  • 接口隔离原则:要求我们在设计接口的时候要精简单一
  • 迪米特法则:要求我们要降低耦合
  • 开闭原则:要求我们对扩展开放,对修改关闭

开始学设计模式

设计模式

  1. 创建型
    • 单例模式
    • 简单工厂模式
    • 工厂方法模式
    • 抽象工厂模式
    • 建造者模式
    • 原型模式
  2. 结构型
    • 适配器模式
    • 组合模式
    • 装饰模式
    • 代理模式
    • 享元模式
    • 外观模式
    • 桥接模式
  3. 行为型
    • 观察者模式
    • 策略模式
    • 状态模式
    • 模板方法模式
    • 命令模式
    • 解释器模式
    • 迭代模式
    • 责任链模式
    • 访问者模式
    • 中介者模式
    • 备忘录模式

【单例模式】

单例模式可以说是最容易理解的模式了,也是用的最多的模式之一。
什么是单例模式?确保单例类只有一个实例,并且这个单例类提供一个函数接口让其他类获取到这个唯一的实例。

什么时候需要使用单例模式呢?如果某个类,创建时需要消耗很多资源,即new出这个类的代价很大;或者是这个类占用很多内存,如果创建太多这个类实例会导致内存占用太多。

懒汉式

public class Singleton{
    // 重点 volatitle 关键字的使用
    private volatile static Singleton instance;

    private Singleton(){};
    
    public static Singleton getInstance(){
        if (instance == null){
            sychronized(Singleton.class){
                if (instance == null)
                    instance=new Singleton();
            }
        }
        return instatnce;
    }
}

基于懒汉式+synchronized的通用单例

public class Singleton<T> {
    private static final ConcurrentMap<Class, Object> INSTANCE_MAP = new ConcurrentHashMap<Class, Object>();

    private Singleton(){}

    public static <T> T getInstance(Class<T> type){
        Object o = INSTANCE_MAP.get(type);
        if (o == null){
            synchronized (INSTANCE_MAP){
                try {
                    o = type.newInstance();
                    INSTANCE_MAP.put(type, o);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return (T) o;
    }
}

在Android中的应用

//获取WindowManager服务引用
WindowManager wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);

【建造者模式】

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

什么情况下使用该模式呢?
主要是在创建某个对象时,需要设定很多的参数(通过setter方法),但是这些参数必须按照某个顺序设定,或者是设置步骤不同会得到不同结果。

public class Student {
    private final long id;  // 必须参数
    private final String name;  //  非必须
    private final int age;

    private Student(Builder builder) {
        this.id = builder.id;
        this.name = builder.name;
        this.age = builder.age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public long getId() {
        return id;
    }

    public static class Builder{
        private final long id;  // 必须参数
        private String name;  //  非必须
        private int age;
        // 返回自身的引用this,这主要是用于链式调用
        public Builder(long id) {
            this.id = id;
        }

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

        public Builder setAge(int age) {
            this.age = age;
            return this;
        }

        public Student build(){
            Student student = new Student(this);
            // Builder另一个特性可以对参数进行合法性验证
            if (student.getAge() > 120){
                // Builder模式是非线程安全的,如果要在Builder内部类中检查一个参数的合法性,必需要在对象创建完成之后再检查
                throw  new IllegalStateException("年龄超出限制");
            }
            return student;
        }
    }
}

注意:

  1. Student的构造方法是私有的,也就是说我们不能直接new出来
  2. Student的属性用final修饰,并且我们在构造方法中都为他们进行了初始化操作,只提供了getter方法
  3. 使用builder模式构造出来的对象有更好的可读性
  4. Builder的属性中只给我们必须的属性添加的final修饰,所以必须在构造方法中为他们初始化
    // 优美的链式调用
  Student student = new Student.Builder(1)
                .setName("张三")
                .setAge(18)
                .build();

在Android中的应用

  • Android中的AlertDialog.Builder
private void showDialog(){
        AlertDialog.Builder builder=new AlertDialog.Builder(context);
        builder.setIcon(R.drawable.icon);
        builder.setTitle("Title");
        builder.setMessage("Message");
        builder.setPositiveButton("Button1", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //TODO
            }
        });
        builder.setNegativeButton("Button2", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //TODO
            }
        });
        
        builder.create().show();
}

  • OkHttp中OkHttpClient的创建
OkHttpClient  okHttpClient = new OkHttpClient.Builder()
                 .cache(getCache()) 
                 .addInterceptor(new HttpCacheInterceptor())
                 .addInterceptor(new LogInterceptor())
                 .addNetworkInterceptor(new HttpRequestInterceptor()) 
                 .build();

【工厂模式】

定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方式模式使一个类的实例化延迟到其子类。

public abstract class Product{
    // 产品类的公共方法
    public void method1(){
        // 业务逻辑
    }
    public abstract void method2();
}

public class ConcreteProductA extends Product {
    @Override
    public void method2() {
        // 产品A的业务逻辑
    }
}
public class ConcreteProductB extends Product {
    @Override
    public void method2() {
        // 产品B的业务逻辑
    }
}
public abstract class Creator {
    // 创建一个产品对象
    public abstract <T extends Product > T createProduct(Class<T> clazz);
}
public class ConcreteCreator extends Creator {
    @Override
    public <T extends Product> T createProduct(Class<T> clazz) {
        Product product = null;
        try {
            product = (Product) Class.forName(clazz.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T) product;
    }
}

在Android中的应用

    //抽象产品:Runnable
    public interface Runnable {
        public abstract void run();
    }
    
    //具体产品:Thread
    public class Thread implements Runnable {
        //构造方法
        public Thread(Runnable target, String name) {
            init(null, target, name, 0);
        }
        
        @Override
        //实现抽象产品的抽象方法
        public void run() {
            if (target != null) {
                target.run();
            }
        }
        
        //其他代码略
    }
    
    
    //抽象工厂:ThreadFactory
    public interface ThreadFactory {
        Thread newThread(Runnable r);
    }
    
    //具体工厂:AsyncTask中的实现
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
        
        //实现抽象工厂的抽象方法
        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());//返回Thread这个产品
        }
    };

【抽象工厂模式】

为创建一组相关或者是相互依赖的对象提供一个接口,而不需要制定他们的具体类。

//抽象产品类-- CPU
public abstract class CPU {
    public abstract void showCPU();
}
//抽象产品类-- 内存
public abstract class Memory {
    public abstract void showMemory();
}
//抽象产品类-- 硬盘
public abstract class HD {
    public abstract void showHD();
}

创建具体产品类

//具体产品类-- Intet CPU
public class IntelCPU extends CPU {

    @Override
    public void showCPU() {
        System.out.println("Intet CPU");
    }
}

//具体产品类-- AMD CPU
public class AmdCPU extends CPU {

    @Override
    public void showCPU() {
        System.out.println("AMD CPU");
    }
}

//具体产品类-- 三星 内存
public class SamsungMemory extends Memory {

    @Override
    public void showMemory() {
        System.out.println("三星 内存");
    }
}

//具体产品类-- 金士顿 内存
public class KingstonMemory extends Memory {

    @Override
    public void showMemory() {
        System.out.println("金士顿 内存");
    }
}

//具体产品类-- 希捷 硬盘
public class SeagateHD extends HD {

    @Override
    public void showHD() {
        System.out.println("希捷 硬盘");
    }
}

//具体产品类-- 西部数据 硬盘
public class WdHD extends HD {

    @Override
    public void showHD() {
        System.out.println("西部数据 硬盘");
    }
}

创建抽象工厂类

//抽象工厂类,电脑工厂类
public abstract class ComputerFactory {
    public abstract CPU createCPU();

    public abstract Memory createMemory();

    public abstract HD createHD();
}

创建具体工厂类

//具体工厂类--联想电脑
public class LenovoComputerFactory extends ComputerFactory {

    @Override
    public CPU createCPU() {
        return new IntelCPU();
    }

    @Override
    public Memory createMemory() {
        return new SamsungMemory();
    }

    @Override
    public HD createHD() {
        return new SeagateHD();
    }
}

//具体工厂类--华硕电脑
public class AsusComputerFactory extends ComputerFactory {

    @Override
    public CPU createCPU() {
        return new AmdCPU();
    }

    @Override
    public Memory createMemory() {
        return new KingstonMemory();
    }

    @Override
    public HD createHD() {
        return new WdHD();
    }
}

//具体工厂类--惠普电脑
public class HpComputerFactory extends ComputerFactory {

    @Override
    public CPU createCPU() {
        return new IntelCPU();
    }

    @Override
    public Memory createMemory() {
        return new KingstonMemory();
    }

    @Override
    public HD createHD() {
        return new WdHD();
    }
}

优点:

  1. 封装性,每个产品的实现类不是高层模块要关心的,它要关心的是接口是抽象。
  2. 产品族内的约束为非公开状态。例如联想电脑使用的是IntelCpu+三星内存+希捷的盘,具体的产品族内的约束是在工厂内实现的。

缺点:
抽象工厂模式的最大缺点就是产品族扩展非常困难,为什么这么说呢?比如我们增加一个主板,抽象类需要增加createBoard(),然后实现类都需要去修改,这就严重违反了开闭原则,而且我们一直说明抽象类和接口是一个契约,改变契约有与契约有关系的代码都要修改,这就是有毒代码。上面说的是产品族内扩展困难,但是品牌类型扩建容易,只要增加一个工厂类复制新增加出来的产品生产任务即可。

工厂方法模式与抽象工厂模式比较

  • 在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法具有唯一性。
  • 抽象工厂模式则可以提供多个产品对象,而不是单一的产品对象

【观察者模式】

待续。。。

【代理模式】

待续。。。

【策略模式】

待续。。。

【原型模式】

待续。。。

【状态模式】

待续。。。

【命令模式】

待续。。。

【装饰模式】

待续。。。

【适配器模式】

待续。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容