永远不要使用(未封装)的String或long,int. 为什么呢? 因为这些基础类型(Primitive)没有语义(Semantic meaning). 它们很难被理解,维护和扩展.
空口无凭,举例为证: 假设有个例子是订阅电影票的服务.
试着比较:
public void bookTicket( String name, String firstName, String film, int count, String cinema);
与:(当然实际使用时,用一个Order对象会更好:-)
public void bookTicket( Name name, FirstName firstName, Film film, Count count, Cinema cinema);
很明显,第二个要容易阅读的多. 尤其是当在IDE中使用自动补全的时候,bookTicket(String arg0, String arg1, String arg2, int arg3, String arg4)
比bookTicket(Name arg0, FirstName arg1, Film arg2, Count arg3, Cinema arg4)
差的太明显了.当某个接口被置于一个不带源码的jar包内时,这种情况很常见.
再尝试比较:
void book(String orderId);
与:
void book(OrderId order);
第一种情况下,开发人员看到这行代码会考虑:a.)怎样获得一个orderId 和b.)orderId到底是什么玩意, "1212", "ABC-123" or "12-34-45-SCHWEINEBACKE". 第二种情况,他可以去查看OrderId类的Javadoc或者使用手册获取它的正确用法. 或许觉得, 这不过是个orderId罢了. 但在遗留系统中,名称和语义是经常不一致的. 我曾经见过一个系统里面把order ID命名为"orderId", "auftragsId", "id"以及其他什么东西,而且居然指的是同一个东西: order ID!
多使用类替代基本类型不光有语义上的优势. 扩展上也更佳: 比如你可以更轻松的将OrderId类里的int替换成long, 增加校验和id生成逻辑. 相比而言,最初若使用String类型要做这些就困难的多.
使用fluent interface实现
fluent interface可以使代码更短,编写更容易. Google Collections的MapMaker是个不错的例子:
ConcurrentMap graphs = new MapMaker() .concurrencyLevel(32) .softKeys() .weakValues() .expiration(30, TimeUnit.MINUTES) .makeComputingMap( new Function() { public Graph apply(Key key) { return createExpensiveGraph(key); } });
使用fluent interface实现的如下所示,像简单的领域类(Domain classes)或者像不可变值的对象. 仅仅是封装了String并增加了一些语义的信息给String.
public class Name { public Name(String name) { ... } public static Name name(String name) { return new Name(name); } }
有人或许觉得这种方式太过繁杂(noisy)了. 比如:
new Customer(new FirstName("Stephan"), new Name("Schmidt"));
要比如下的直接使用String参数的方式繁杂.
new Customer("Stephan", "Schmidt");
但,不可否认,第一个要更加容易理解, 若使用静态方法,第一个方法也可以变为:
new Customer(firstName("Stephan"), name("Schmidt"));
这样也较好的解决了参数较多时让人糊涂的问题.
[文章翻译自:http://codemonkeyism.com/never-never-never-use-string-in-java-or-at-least-less-often/ 请任意转载]