为类成员提供对另一个类成员的引用

Joh*_*ick 2 java oop

从1到10的等级,从安全编程实践的角度来看,以下有多糟糕?如果你发现它比五更糟糕,你会做什么呢?

下面我的目标是获得的地图列表中的数据在B插入A.在这种情况下,对我来说,这是确定的,如果它要么是一个数据的副本或原始数据的参考.我发现这种方法最快,但我对此感到不安.

public class A {
    private List<Map<String, String>> _list = null;
    public A(B b) {
        _list = b.getList();
    }
}

public class B {
    private List<Map<String, String>> _list = new ArrayList<Map<String, String>>();
    public List<Map<String, String>> getList() { 
        // Put some data in _list just for the sake of this example...
        _list.add(new HashMap<String, String>());
        return _list; 
    }
}
Run Code Online (Sandbox Code Playgroud)

Aar*_*lla 5

潜在的问题有点复杂:

  • 从安全角度来看,这非常非常糟糕.
  • 从性能角度来看,这非常非常好.
  • 从测试的角度来看,这很好,因为课堂上没有任何内容可以让你从测试中轻易获得
  • 从封装的角度来看,由于暴露了类的内部状态,因此它很糟糕.
  • 从编码安全的角度来看,这很糟糕,因为有人会最终滥用这一点来获得一些"整洁"的技巧,这会在其他地方引起奇怪的错误,你将浪费大量的时间来调试它.
  • 从API的角度来看,它可以是:很难想象API更简单,但同时,它不会传达您的意图,如果您需要更改基础数据结构,事情将会严重破坏.

在设计软件时,您需要将所有这些要点放在脑海中.随着时间的推移,您将会感受到您所犯的错误以及如何避免错误.计算机像转储一样缓慢而且速度很慢,但从来没有一个完美的解决方案.您可以努力使它在您编写时尽可能好.

如果您想要进行防御性编码,则应始终复制您获得或公开的任何数据.当然,如果"数据"是您的整个数据模型,那么每次调用方法时都无法复制所有内容.

解决这个僵局的方法:

  • 尽可能多地使用不可变量.创建了不可变项和值对象,之后永远不会更改.除非创建非常昂贵,否则它们总是安全且性能良好.懒惰的创造在这里会有所帮助,但这通常是它自己的蠕虫.Guava提供了一套全面的系列,在创建后无法更改.

    不要太依赖,Collections.unmodifiable*因为支持集合仍然可以改变.

  • 使用写时复制数据结构.如果A或B开始更改它,基础列表将自行克隆,上述问题就会消失.这将使每个自己的副本有效地将它们彼此隔离.不幸的是,Java并不支持这些内置的.