zoukankan      html  css  js  c++  java
  • Offensive Coding

    参考自:http://www.artima.com/weblogs/viewpost.jsp?thread=168511

       一直以来只知道防御式编程,《代码大全》中也专门有一章讲述防御式编程,防御式编程又称被动编程。有一个比喻是说开车时司机只遵守交通规则是远远不够的,还得时刻提防其他意外因素,如马路杀手、其他醉酒的司机等等。对应在编程中就是“不能信任用户的输入,必须执行相应的参数检查”。

       而offensive coding则与此相反,它的中文意思是攻击式编程或者主动编程。

       先看一段简单的代码:

    private void addResolution(List<Flag> flags) {
        if (flags != null) {
            if (supportedAdapters.contains(Adapter.LOW) 
                    || supportedAdapters.contains(Adapter.MEDIUM)) {
                flags.add(new ResolutionFlag(ADAPTED));
            } 
        }
    } 

       这段代码有啥问题?也许有人的第一反应是这段代码应该使用Guard Clause,即改成下面这样:

    private void addResolution(List<Flag> flags) {
        if(flags == null)
            return;
    
        if (supportedAdapters.contains(Adapter.LOW) 
                    || supportedAdapters.contains(Adapter.MEDIUM)) {
            flags.add(new ResolutionFlag(ADAPTED));
        }
    } 

       但其实问题不在于此,而在于这一行代码:

    if(flags == null) {...

       既然是private方法,那么完全可以在类内部自己保证传入的参数flags不为null,而不用进行多余的null check。

    滥用null check是糟糕代码的标识。

       null check是不可或缺的。如果你在你的代码中到处传递null,那么接收参数并处理的方法进行null check是必要的。但是这也意味着你的代码很糟糕。你在给自己增加额外负担(所有有参数的方法开头都必须进行null check),你的代码也很难复用。

       另外一个例子:

    public String [] getParameters() {
        if (intParms.length  == 0) {
            return null;
        }
        String [] result = new String[intParms.length];
        for(int n = 0; n < intParms.length; n++) {
            result[n] = "parameter " + intParms[n];
        }
        return result;
    }

       这段代码有什么问题呢?如果这个方法被你自己在同一个项目中其他地方使用还好,你知道返回值可能为null,所以你会进行null check。而如果是你的同事在使用这段代码,或者这段代码被打包在Jar中被世界上某个角落的另一个程序员使用呢?他们不会像你一样对你的代码这么熟悉。他们很可能忘记null check,比如如下:

    // 世界上某个角落的其他程序员Fork在使用你的Jar包中的getParameters方法
    public void foo() {
       ...
       int len = new ConcreteService().getParameters().length;
       ...
    }

       很可能这段代码在大部分情况下都能正常运行,而不会抛出NullPointerException,于是这位程序员又将这段代码打包到他的Jar包里,之后又有第三个程序员John来使用Fork的Jar包中的foo()方法,如下:

    // John使用Fork的Jar包中的代码
    public void bar() {
    ... new Delegator().foo();
    ... }

       OK,问题来了,大部分时候这段代码也执行正常,但是某一天bar()突然抛出NullPointerException,你最初挖的“坑”潜伏这么久,终于有人掉进去了。John只能骂一句“好坑!”或者“Oh, shift!”了。那么最初的getParameters()方法该怎么写才好呢?很简单,像下面这样即可:

    public String [] getParameters() {
        String [] result = new String[intParms.length];
        for(int n = 0; n < intParms.length; n++) {
            result[n] = "parameter " + intParms[n];
        }
        return result;
    }

        现在如果intParms是一个空数组的话,返回的也是一个空数组。但如果intParms是null怎么办呢?很简单,intParms显然是类变量或者类成员,你只需要保证intParms始终不为null即可,比如这样:

    private int[] intParms = new int[0];

        然后任何对intParms的修改都不能将其设为null,但可以把它重置为空数组。这样当前类内部的处理负担可能加重了,但其他类的负担却大大减轻,别人也将更乐意使用你的代码。

  • 相关阅读:
    Redis与Redis 伪集群环境的搭建
    github的基本使用
    使用七牛云存储图片或文件并回显
    阿里云搭建wordpress博客教程
    判断是否同一天 同一月
    Python学习笔记之 并发编程
    Python学习笔记之 日志模块logging使用详解
    Python学习笔记之 网络编程(socket套接字编程)
    Python实现TCP文件传输
    实例:Python实现聊天室
  • 原文地址:https://www.cnblogs.com/feichexia/p/OffensiveProgrammiing.html
Copyright © 2011-2022 走看看