设计模式--空对象模式(Null Object Pattern)-初阶


一.问题的引入

空对象模式到底是什么呢?在解开它的神秘面纱之前,我们先来看一个场景:

李华刚工作了几年,靠努力积攒了一笔资金。这时候,他萌生了创业的想法。并经过团队的不懈努力,公司越做越大,数据库存储的职工也越来越多。李华,闲得蛋疼,没事想查询一下员工信息,于是发生了下面的故事。

1.创建员工所对应的实体类

package com.yc.null_object_test;
/**
 * Created by yucheng on 2018/8/10.
 */
public class Person {
    private int id;
    private String name;
    private String adress;

    public Person(int id, String name, String adress) {
        this.id = id;
        this.name = name;
        this.adress = adress;
    }
    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public String getAdress() {
        return adress;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", adress='" + adress + '\'' +
                '}';
    }
}

2.创建PersonFactory,用来获取Person对象

package com.yc.null_object_test;
/**
 * Created by yucheng on 2018/8/10.
 */
public class PersonFactory {
    /**
     * 
     * @param id:员工号
     * @return:用来返回员工对象
     */
    public Person getPerson(int id){
        Person p = null;
        switch (id){
            case 3:
                p = new Person(3,"张三","上海");
                break;
            case 4:
                p = new Person(4,"李四","北京");
                break;
            case 5:
                p = new Person(5,"王五","青岛");
                break;
            default:
                break;
        }
        return p;
    }
}

3.创建客户端,用来查询员工信息

 * Created by yucheng on 2018/8/10.
 */
public class Cilent {
    public static void main(String[] args) {
        PersonFactory pf = new PersonFactory();
        Person zs = pf.getPerson(3);
        Person ls = pf.getPerson(4);
        System.out.println("name = " + zs.getName());
        System.out.println("lisi = " + ls.getName());
    }
}

4.输出结果

name = 张三
lisi = 李四

结果一切看起来很美好,但是公司具体有多少人他自己也不是很清楚,于是乎,李华进行了下面的查询:

public class Cilent {
    public static void main(String[] args) {
        PersonFactory pf = new PersonFactory();
        Person x = pf.getPerson(100);
        System.out.println("x = " + x.getName());
    }
}
Exception in thread "main" java.lang.NullPointerException
    at com.yc.null_object_test.Cilent.main(Cilent.java:10)

我嘞个去,发生了什么,李华一脸懵逼!!!
  没错,是的。这就是我们在编程过程中,经常会遇见的一个问题,空指针异常。原因在于,我们传入了非法id=100。在PersonFactory中找不到对应的case值,从而导致对象x为null。而当我们使用空对象的引用时,就会报空指针异常。因此我们需要在操作对象之前对其进行判断如下:

public class Cilent {
    public static void main(String[] args) {
        PersonFactory pf = new PersonFactory();
        Person x = pf.getPerson(100);
        if (x == null){
            System.out.println("对象为空!x = " + x);
        }
        else {
            System.out.println("x = " + x.getName());
        }
    }
}

但是,你有没有想过,当我们对象的操作比较少时,这种判断的方法是很简洁有效,但当我们需要进行一系列操作时,又会增加多大的工作量呢?那么,有没有一劳永逸的做法呢
  是的,正如你所想,空对象模式能够很好地解决我们的问题。

二.空对象模式

Problem
1.在编程的过程中,每次使用引用时,测试其是否为空总是我们避不开的一个话题,及其枯燥,而且势必将产生相当乏味的代码。
2.一旦我们忘记判断,NullPointerException就会映入眼帘,而你就得老老实实地的去慢慢检查。真的很闹心,反正我是这样认为的。

Solutions
空对象
  它可以接收传递给它的所代表对象的信息,但是将返回表示为实际上并不存在任何“真实”的对象的值。通过这种方式,你可以假设所有的对象都是有效的,而不必浪费巨大精力去检查null。

三.解决问题
我们仍然围绕上面的那个问题来讨论,寻求解决方案:
1.空对象模式(Null Object Pattern)的类结构图

57.png

2.代码实现
在上面程序的基础上进行修改
<1> 创建抽象接口

package com.yc.null_object3;
/**
 * Created by yucheng on 2018/8/10.
 */
public interface AbstractPerson {
    String getName();// 用来获取对象的名字
    boolean isNull();// 判断对象是否为空
}

<2> 创建空对象类

package com.yc.null_object3;
/**
 * Created by yucheng on 2018/8/10.
 */
public class NullPerson implements AbstractPerson {
    @Override
    public String getName() {
        return "NullPerson{对象为空!}";
    }
    @Override
    public boolean isNull() {
        return true;
    }
}

<3> 创建实际对象类

package com.yc.null_object3;

/**
 * Created by yucheng on 2018/8/10.
 */
public class Person implements AbstractPerson {
    private int id;
    private String name;
    private String adress;

    public Person(int id, String name, String adress) {
        this.id = id;
        this.name = name;
        this.adress = adress;
    }
    public String getName() {
        return name;
    }
    @Override
    public boolean isNull() {
        return false;
    }
}

<4> 创建对象工厂

package com.yc.null_object3;

/**
 * Created by yucheng on 2018/8/10.
 */
public class PersonFactory {

    public AbstractPerson getPerson(int id) {
        AbstractPerson p = null;
        switch (id){
            case 3:
                p = new Person(3,"张三","上海");
                break;
            case 4:
                p = new Person(4,"李四","北京");
                break;
            case 5:
                p = new Person(5,"王五","上海");
                break;
            default:
                p = new NullPerson();//当有不合法输入时,用空对象来填充
                break;
        }
        return p;
    }
}

<5> 创建客户端类

package com.yc.null_object3;

/**
 * Created by yucheng on 2018/8/10.
 */
public class Cilent {
    public static void main(String[] args) {
        // 合法输入
        PersonFactory pf = new PersonFactory();
        AbstractPerson p1 = pf.getPerson(3);
        AbstractPerson p2 = pf.getPerson(4);
        // 非法输入
        AbstractPerson p3 = pf.getPerson(100);

        System.out.println("p1 = " + p1.getName());
        System.out.println("p2 = " + p2.getName());
        System.out.println("p3 = " + p3.getName());
    }
}

<6> 结果展示

p1 = 张三
p2 = 李四
p3 = NullPerson{对象为空!}

  由输出结果,我们可以知晓,即使我们进行了非法输入,也不会报错了,这是空对象模式的第一个好处。
  另外在NullBook类的show方法中,我们可以定制我们的输出提醒,当用户调用空对象的show方法时,就会输出我们定制的提醒。这回我们可以实现,一处定制,处处输出,主动权在我们手里,而不是在客户端的手里。这是Null Object Pattern的第二个好处。

其实呢,我们在客户端不进行判断,程序也不会报错,但是最佳的方式,还是进行判断。

package com.yc.null_object3;

/**
 * Created by yucheng on 2018/8/10.
 */
public class Cilent {
    public static void main(String[] args) {
        // 合法输入
        PersonFactory pf = new PersonFactory();
        AbstractPerson p3 = pf.getPerson(100);
        if(p3.isNull()){
            System.out.println("兄弟!你进行了非法id访问!");
        }
        else{
            System.out.println("p3 = " + p3.getName());
        }
    }
}

三.总结

Null Object Pattern,作为一种被遗忘的设计模式,却有着不能被遗忘的作用。

(1)它可以加强系统的稳固性,能有有效地防止空指针报错对整个系统的影响,使系统更加稳定。
(2)它能够实现对空对象情况的定制化的控制,能够掌握处理空对象的主动权。
(3)它并不依靠Client来保证整个系统的稳定运行。
(4)它通过isNull对==null的替换,显得更加优雅,更加易懂。

说明:这里所讲的空对象模式(Null Object Pattern)是极为简单的内容,后期我将更为深入的讲解,敬请期待!希望能对你有所帮助。
推荐阅读:
设计模式--空对象模式(Null Object Pattern)-中阶
设计模式--代理模式(Proxy Pattern)
设计模式--代理模式(Proxy Pattern) 之 “高老庄悟空降八戒”

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,654评论 18 139
  • 深夜食堂·蛋炒饭 平生第一次动火下厨房,便是做的蛋炒饭。那时上初一,好不容易鼓起勇气点着了煤气灶,却怎么也鼓不...
    机灵费费阅读 378评论 0 0