【设计模式】

设计模式(适用场景 优点)

从Android代码中来记忆23种设计模式

单例模式

确保单例类只有一个实例,并且这个单例类提供一个函数接口让其他类获取到这个唯一的实例。

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

//此为懒汉式 饿汉式在声明时直接初始化
public class Singleton{
    //volatile保证了其他线程拿到的也是最新的实例
    private volatile static Singleton instance;
    //将默认的构造函数私有化,防止其他类手动new
    private Singleton(){};
    public static Singleton getInstance(){
        if(instance==null){
            synchronized(Singleton.class){
                if(instance==null){
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}

为什么需要2次判断是否为空呢?第一次判断是为了避免不必要的同步,第二次判断是确保在此之前没有其他线程进入到sychronized块创建了新实例。
使用类级内部类,只有内部类被调用到(即Singleton.singleton)才会装载

public class MySingleton {  
    /** 
     * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 
     * 没有绑定的关系,而且只有被调用到才会装载,从而实现了延迟加载 
     */  
    private static class Singleton{  
        /** 
         * 静态初始化器,用JVM来保证线程安全 
         */  
        private static MySingleton singleton = new MySingleton();  
          
        static {  
            System.out.println("---->类级的内部类被加载");  
        }  
        private Singleton(){  
            System.out.println("---->类级的内部类构造函数被调用");  
        }  
    }  
    //私有化构造函数  
    private MySingleton(){  
        System.out.println("-->开始调用构造函数");  
    }  

    public static MySingleton getInstance(){  
        System.out.println("-->开始调用公有方法返回实例");  
        System.out.println("-->返回单例");  
        return Singleton.singleton;
    }  
}  

记忆:getSystemService的内部实现

建造者模式(Builder)

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

主要是在创建某个对象时,需要设定很多的参数(通过setter方法),但是这些参数必须按照某个顺序设定,或者是设置步骤不同会得到不同结果(模式不同后续的可用属性也有不同)

记忆:在创建对话框时的代码

身边例子:通过方法构建一个页面,有无list,有无tab,有无column,每一个先导选择都会导致后续使用参数的不同

工厂方法模式

定义一个创建对象的接口,让子类决定实例化哪个类
其实,在getSystemService方法中就是用到了工厂模式,他就是根据传入的参数决定创建哪个对象,当然了,由于返回的都是以单例模式存在的对象,因此不用new了,直接把单例返回就好。

抽象工厂模式

为创建一组相关或者是相互依赖的对象提供一个接口,而不需要制定他们的具体类 (满足依赖倒置原则)

public abstract class AbstractProductA{//标题栏
    public abstract void method();
}
public abstract class AbstractProdectB{//无数据
    public abstract void method();
}
public abstract class AbstractFactory{//listTemplate
    public abstract AbstractProductA createProductA();

    public abstract AbstractProductB createProductB();
}
public  class ConcreteFactory1 extends AbstractFactory{//listT实例1
    public  AbstractProductA createProductA(){
        return new ConcreteProductA1();
    }
    public  AbstractProductB createProductB(){
        return new ConcreteProductB1();
    }
}
public  class ConcreteFactory2 extends AbstractFactory{//listT实例2
    public  AbstractProductA createProductA(){
        return new ConcreteProductA2();
    }

    public  AbstractProductB createProductB(){
        return new ConcreteProductB2();
    }
}

策略模式

定义:有一系列的算法,将每个算法封装起来(每个算法可以封装到不同的类中),各个算法之间可以替换,策略模式让算法独立于使用它的客户而独立变化。
其中在属性动画中使用时间插值器的时候就用到了。在使用动画时,你可以选择线性插值器、加速减速插值器、减速插值器以及自定义的插值器。这些插值器都是实现根据时间流逝的百分比来计算出当前属性值改变的百分比。通过根据需要选择不同的插值器,实现不同的动画效果。

使用者可能会觉得有工厂方法的影子,因为上文中提到的线性插值器、加速减速插值器、减速插值器以及自定义的插值器,很明显可以通过工厂方法构建出来,但是策略模式是代表了将每个算法封装起来(每个算法可以封装到不同的类中),各个算法之间可以替换,策略模式让算法独立于使用它的客户而独立变化,侧重点不同。所以我们要知道,同时使用多种设计模式是很常见的。
身边的例子:生成申请类的工厂方法,只需要一个变量的改变,如果申请类内部存在算法,则应用了策略模式。可以说工厂方法可以作为策略模式的实现方式,但他不是唯一的
反例:使用了建造者模式的工厂方法

适配器模式

定义:把一个类的接口变换成客户端所期待的另一个接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
比较典型的有ListView和RecyclerView的adapter。为什么ListView需要使用适配器呢?主要是,ListView(view)只关心它的每个ItemView,而不关心这个ItemView具体显示的是什么。而我们的数据源(model)存放的是要显示的内容,它保存了每一个ItemView要显示的内容。ListView和数据源之间没有任何关系,这时候,需要通过适配器(adapter),适配器提供getView方法给ListView使用,每次ListView只需提供位置信息给getView函数,然后getView函数根据位置信息向数据源获取对应的数据,根据数据返回不同的View。

观察者模式

定义:定义了对象之间的一对多的关系,其实就是1对n,当“1”发生变化时,“n”全部得到通知,并更新
观察者模式一个比较经典的应用就是:订阅——发布系统。很容易理解,发布消息时,将消息发送给每个订阅者
那么Android哪里用到了观察者模式呢?我们看看ListView的适配器,有个函数notifyDataSetChanged()函数,这个函数其实就是通知ListView的每个Item,数据源发生了变化,请各位Item重新刷新一下。

观察者模式的实现

//抽象主题
public interface MySubject {
    void registerObserver(MyObserver o);
    void removeObserver(MyObserver o);
    void notifyObserver();
}
//抽象观察者
public interface MyObserver {
    void update(String authorName, String articleName);
}
//实现主题
public class WeChatServer implements MySubject {

    private List<MyObserver> myObservers;
    private String authorName;
    private String articleName;

    public WeChatServer(String authorName) {
        myObservers = new ArrayList<>();
        this.authorName = authorName;
    }

    public void publishArticle(String articleName) {
        this.articleName = articleName;
        notifyObserver();
    }

    @Override
    public void registerObserver(MyObserver o) {
        myObservers.add(o);
    }

    @Override
    public void removeObserver(MyObserver o) {
        if (myObservers.contains(o)) {
            myObservers.remove(o);
        }
    }

    @Override
    public void notifyObserver() {
        myObservers.forEach(item -> {
            item.update(authorName, articleName);
        });
    }
}
//具体的观察者
public class WeChatClient implements MyObserver {
    private String username;
    public WeChatClient(String username) {
        this.username = username;
    }

    @Override
    public void update(String authorName, String articleName) {
        System.out.println(username + ": " + authorName + " 发了一篇文章 " + articleName);
    }
}
public class Main {
    public static void main(String[] args) {
        WeChatServer weChatServer = new WeChatServer("Java识堂");
        WeChatClient user1 = new WeChatClient("张三");
        WeChatClient user2 = new WeChatClient("李四");
        weChatServer.registerObserver(user1);
        weChatServer.registerObserver(user2);
        weChatServer.publishArticle("《五分钟学会观察者模式》");
    }
}

装饰模式

动态的给一个对象添加额外的职责,就增加功能来说,装饰模式比子类继承的方式更灵活。
通过简单代码来理解装饰模式:

public abstract class Component{
    public abstract void operate();
}

public class ConcreteComponent extends Component{
    public void operate(){
        //具体的实现
    }
}

public class Decorator{
    private Component component;
    public Decorator(Component component){
        this.component=component;
    }
    public void operate(){
        operateA();
        component.operate();
        operateB();
    }
    public void operateA(){
        //具体操作
    }
    public void operateB(){
        //具体操作
    }
}

那么在Android哪里出现了装饰模式呢?我们平时经常用到Context类,但是其实Context类只是个抽象类,具体实现是ContextImpl,那么谁是ContextImpl的装饰类呢?我们知道Activity是个Context,但是Activity 并不是继承于Context,而是继承于ContextThremeWrapper.而ContextThremeWrapper继承于ContextWrapper,ContextWrapper继承Context.说了这么多,跟装饰模式有啥关系?主要是引入ContextWrapper这个类。ContextWrapper内部有个Context引用mContext,并且ContextWrapper中对Context的每个方法都有实现,在实现中调用的就是mContext相同的方法。

身边的例子:BaseActivity+MyBaseActivity(通过抽象类+实现类的组合实现职责添加)

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

推荐阅读更多精彩内容