为了程序的健壮性,我们可以使用空对象模式

简介: 为了程序的健壮性,我们可以使用空对象模式

空对象模式 (null object Pattern)是一种软件设计模式。可以用于返回无意义的对象时,它可以承担处理null的责任。有时候空对象也被视为一种设计模式。


在写代码的时候我们经常会遇到空指针,为了避免空指针的发生需要做一些判断。如果是复杂对象的话,还需要一层层地去判断。这个时候我就无比怀念groovy、kotlin这类语言。可以使用形如:

user?.address?.name


这样的语法糖,而无需一层层的判断。

google的guava库提供了Optional类,可以有效的判断null对象。

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5


guava可以创建指定的null对象

Optional<Integer> nullable=Optional.fromNullable(null);
System.out.println("from Nullable Optional isPresent:"+nullable.isPresent());  //returns from Nullable Optional isPresent:false


在java 8中也新增了Optional类。


同时,我自己也仿照guava的Optional类写了一个简化版的Optional并附上使用方法,它借助了rxjava。

import rx.Observable;
/**
 * 使用方法:
 *      String s = null;
 *      Optional.ofNullable(s).orElse("default")); // 如果s为null,则显示default,否则显示s的值
 * @author Tony Shen
 *
 */
public class Optional<T> {
    Observable<T> obs;
    public Optional(Observable<T> obs) {
        this.obs = obs;
    }
    public static <T> Optional<T> of(T value) {
        if (value == null) {
            throw new NullPointerException();
        } else {
            return new Optional<T>(Observable.just(value));
        }
    }
    public static <T> Optional<T> ofNullable(T value) {
        if (value == null) {
            return new Optional<T>(Observable.<T>empty());
        } else {
            return new Optional<T>(Observable.just(value));
        }
    }
    public T get() {
        return obs.toBlocking().single();
    }
    public T orElse(T defaultValue) {
        return obs.defaultIfEmpty(defaultValue).toBlocking().single();
    }
}


上面讲了那么多,是为了防止空指针出现,现在我们来看看空对象模式具体的使用场景吧,假设我们在代码中使用了链式调用,形如:

client = RestClient.post(request.getUrl())
        .readTimeout(request.getReadTimeoutMillis())
        .connectTimeout(request.getConnectTimeoutMillis())
        .addHeaders(request.getHeaders());


只要某一个环节出现问题,就会有空指针的隐患的。比如RestClient的post()方法内部出


现了问题,那就非常严重了,后面整个链路都会断掉,报空指针异常。


那我们如何保证整个链路不断呢?在post()方法里面会调用一个getConnection()方法

public HttpURLConnection getConnection() {
        if (connection == null)
            connection = createConnection();
        if (connection == null) {
            clientIsNull = true;
            connection = NullConnection.createNull(url);
        }
        return connection;
    }


请注意,在getConnection()方法里会有两个connection == null的判断。理论上,第一次调用createConnection()方法时,connection是不会为空的。但是在使用某个APM sdk时,确实发现有极少的概率connection会为空。如果它为空,那么我们在第二个判断中增加了如下的代码,来保证返回的connection不为null,提高程序的健壮性。

connection = NullConnection.createNull(url);


我们来看看,NullConnection是怎么回事

/**
 * Created by Tony Shen on 2016/12/6.
 */
public class NullConnection extends HttpURLConnection {
    private NullConnection(URL url) {
        super(url);
    }
    @Override
    public void disconnect() {
    }
    @Override
    public boolean usingProxy() {
        return false;
    }
    @Override
    public void connect() throws IOException {
    }
    public boolean isNull() {
        return true;
    }
    public static NullConnection createNull(URL url) {
        return new NullConnection(url);
    }
}


其实,基本没做啥事,主要多了一个createNull()的方法。它会产生一个NullConnection对象,它的作用是防止产生null,从而保证原先的RestClient链路是正常的。这就是空对象模式。


链式调用,会让代码更加清晰,带给我们的好处是非常明显的。只要我们处理好空指针的隐患,就可以更愉悦地写代码了O(∩_∩)O哈哈~

相关文章
|
3月前
|
设计模式 缓存 安全
单例模式的应用与陷阱:确保你的代码只有一个实例
单例模式的应用与陷阱:确保你的代码只有一个实例
77 0
|
3月前
|
SQL NoSQL Java
系统干崩了,只认代码不认人
为了保障系统的高可用和稳定,我发誓以后只认代码不认人。文末总结了几个小教训,希望对你有帮助。
系统干崩了,只认代码不认人
|
10月前
|
编译器 C++
2022 VS编译器如何实现监视
2022 VS编译器如何实现监视
|
12月前
|
安全 Java API
了解程序运行逻辑的必要性及应用和硬件的关系
了解程序运行逻辑的必要性及应用和硬件的关系
61 0
|
消息中间件 JavaScript 小程序
这些老系统代码,是猪写的么?
这些老系统代码,是猪写的么?
|
测试技术
接口测试平台181:并发用例底层-临时变量替换
接口测试平台181:并发用例底层-临时变量替换
接口测试平台181:并发用例底层-临时变量替换
|
安全
程序人生 - 怡宝和农夫山泉有什么区别,哪个更好一些?
程序人生 - 怡宝和农夫山泉有什么区别,哪个更好一些?
203 0
嵌入式程序调用函数的内部过程和机制
嵌入式程序调用函数的内部过程和机制
嵌入式程序调用函数的内部过程和机制
|
C# 数据格式 JSON
(转)C# 快速高效率复制对象的方式
1、需求 在项目代码中经常需要把对象复制到新的对象中,或者把属性名相同的值复制一遍。 比如: public class Student { public int Id { get; set; } public string Name...
3485 0