设计模式——空设计模式

1、使用场景
   空设计模式在什么时候会派上用场呢?假设这样一个场景:在一个在线考试系统中,调用一个方法,传过去你要查找用户的ID,然后它返回给你要查找用户的考试成绩,此时你就可以调用对象的方法来输出用户的成绩信息。下面,我们来实现以下具体的代码。

public class User {
    private int ID;
    private String name;
    private String score;

    public User(int ID, String name, String score) {
        this.ID = ID;
        this.name = name;
        this.score = score;
    }

    public void show() {
        System.out.println(ID + "+++" + name + "+++" + score);
    }

}

创建用户对象的用户工厂的代码:

public class UserFactory {

    public User getUser(int ID) {
        User user = null;
        switch (ID) {
        case 1:
            user = new User(ID, "jack", "66");
            break;
        case 2:
            user = new User(ID, "phil", "88");
            break;
        default:
            user = null;// 可以省略。
            break;
        }

        return user;
    }
}

客户端调用代码:

public class Client {

    static void main(String[] args) {
        UserFactory userFactory = new UserFactory();
        User user = userFactory.getUser(1);
        user.show();
    }

}

   运行成功,但是如果我们把User user = userFactory.getUser(1)中的1改成-1。再来运行一下,发现如下报错:空指针报错。它提示我们第28行user.show();报错。因为我们通过userFactory.getUser(1)方法获取User对象的时候,如果我们传入的参数,属于非法值(如-1)或者不存在(如a)的话(其实这种情况是经常遇到的),就会返回null,表示我们查找的用户并不存在。这时,user为null.你再调用user.show()。当然要报空指针的错误了。那怎么解决呢?
   我们比较常规的做法就是在客户端加一个判断,判断是否为null。如果为null的话,就不再调用show()方法。如果不为null再调用show()方法。更改如下:

public static void main(String[] args) {
        UserFactory userFactory = new UserFactory();
        User user = userFactory.getUser(-1);
        //判断user对象是否为null。
        if (user == null) {
            System.out.println("user对象为 null。");
        } else {
            user.show();
        }
    }

此时,再运行,就不会报错了。而是,输出了:user对象为null。
但是,你有没有考虑过?这样做,确实消除了报错,但是这样做真的好吗?你想如果在一段程序中有很多处调用getUser()方法或者有很多个客户端的话,岂不是很多处都要判断user对象是否为null?这还不算坏,如果哪一处没有判断,然后报错了,很有可能导致程序没法继续运行甚至崩溃。那究竟应该如何实现才会更加合适呢?此时就要用到我今天要说的Null Object Pattern——空设计模式

2、空设计模式
下面我们来改一下代码,新增的抽象接口Users类的代码:

interface Users {
    // 判断User对象是否为空对象(Null Object)
    public boolean isNull();

    // 展示user对象的信息
    public void show();
}

新增的空对象类NullUser类的代码(继承Users类):

public class NullUser implements Users {
    public boolean isNull() {
        return true;
    }

    public void show() {

    }
}

原有的User类修改后的代码(增加对Users接口的实现,实现isNull方法):

public class User implements Users{
    private int ID;
    private String name;
    private String score;

    // 构造函数
    public User(int ID, String name, String score) {
        this.ID = ID;
        this.name = name;
        this.score = score;
    }


    public void show() {
        System.out.println(ID + "+++" + name + "+++" + score);
    }
    public boolean isNull(){
        return false;
    }
}

工厂类(UserFactory)修改后的代码(返回对象从User改为Users,并当ID属于非法值或者不存在时,返回NullUser对象。):

public class UserFactory {

    public Users getUser(int ID) {
        Users users;//将原来的User改为Users
        switch (ID) {
        case 1:
            user = new User(ID, "jack", "66");
            break;
        case 2:
            user = new User(ID, "phil", "88");
            break;
        default:
            users = new NullUser();//创建一个NullUser对象
            break;
        }

        return users;
    }
}

客户端的代码为:

public static void main(String[] args) {
        UserFactory userFactory = new UserFactory();
        Users users = userFactory.getUser(-1);
        users.show();
}

   运行我们发现,即使传入的参数是非法值或者不存在的值时,也不会报错了,这是空设计模式(Null Object Pattern)的第一个好处。但是现在不报错,也没有任何输出,肯定不够友好,不够人性化。此时,在NullUser类的show方法中,我们可以定制我们的输出提醒,当用户调用空对象的show方法时,就会输出我们定制的提醒。这回我们可以实现,一处定制,处处输出,主动权在我们手里,而不是在客户端的手里。这是Null Object Pattern的第二个好处。

比如我们进行如下修改,修改后的NullUser类代码:

public class NullUser implements Users {
    public boolean isNull() {
        return true;
    }

    public void show() {
        System.out.println("Sorry,未找到符合您输入的ID的用户信息,请确认您的输入是否正确。");
    }
}

   此时,在执行一下Client,你会发现控制台输出为:Sorry,未找到符合您输入的ID的用户信息,请确认您的输入是否正确。其实,虽然在客户端我们不进行检测也可以保证程序不报错,但是最好的方式,还是进行相应的检测,如下:

public static void main(String[] args) {
        UserFactory userFactory = new UserFactory();
        Users users = userFactory.getUser(-1);
        if (users.isNull()) {
            //这里由客户端定制提示代码
            System.out.println("您的输入不正确。");
        }else{
            users.show();
        }
    }

   相比之下,users.isNull()比users == null更加优雅一点。到这里,Null Object Pattern大概就介绍完了。我们可以看到,其实Null Object Pattern很简单,但是它也可以说使整个系统更加坚固了。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值