Java的含义共生性

含义共生性(Connascence of meaning)是一种用于描述组件之间关系和依赖程度的专业词语,最早见于90年代的Meilir Page-Jones的 What Every Programmer Should Know About Object Oriented Design。该概念常应用在UML设计中,但是并没有在开发社区广泛传播。

含义共生性是指,多个组件必须针对某个值的意义达成一致认可。含义共生性也称为约定共生性,约定俗成的意思。用于描述多个组件共同分享某个特定值的意义。

含义共生性提供了依赖和耦合度的分类学,允许开发人员有逻辑思考他们的代码质量。

看看下面的Java类:


public class Dinosaur {
private int diet;
public Dinosaur(int diet) {
this.diet = diet;
}
public void feed(Food food) {
// Eat the food
}
public int getDiet() {
return diet;
}
}

public class DinosaurHandler {
private Dinosaur dinosaur;
public DinosaurHandler(Dinosaur dinosaur) {
this.dinosaur = dinosaur;
}
public void feedDinosaur() {
switch (dinosaur.getDiet()) {
case 1:
// Dinosaur is a carnivore
dinosaur.feed(new Goat());
break;
case 2:
// Dinosaur is a herbivore
dinosaur.feed(new Cabbage());
break;
}
}
}

这两个类由含义共生性耦合在一起了,他们两个都约定使用数字1表示食肉动物,而数字2代表食草动物;3表示杂食动物。

Java中更普遍的含义共生性是关于null空值的约定。

以下面恐龙类说明


public class DinosaurEgg {
private long timeLaid;
public long getTimeLaid() {
return timeLaid;
}
private boolean isReadyToHatch() {
return (System.currentTimeMillis() / 1000) - timeLaid > 600;
}
public Dinosaur hatch() {
if (isReadyToHatch()) {
return new Dinosaur(this);
} else {
return null;
}
}
}

public class DinosaurRegistry {
public Dinosaur get(String name) {
// Get dinosaur with this name
// Return null if no dinosaur exists
}
public void register(Dinosaur dinosaur) {
// Register a dinosaur恐龙
// Name must be unique
}
}

public class DinosaurLab {
private DinosaurRegistry registry;
public Dinosaur hatch(DinosaurEgg egg) {
Dinosaur dinosaur = egg.hatch();
if (dinosaur == null) {
return null;
}
String name = dinosaur.getName();
if (registry.get(name) == null) {
registry.register(dinosaur);
return dinosaur;
} else {
return null;
}
}
}


上述代码返回了null空值,其实是把空值作为一种业务含义使用了,然后我们再判断某个方法返回是否为空,从而主导业务流程判断。

上述代码中timeLaid 方法中把时间约定成了秒,同时又有了null空值的约定俗成,这两者结合在一起,导致一种可笑的逻辑,空值指向一个事实:蛋不能被孵化,因为它不是在10分钟以前放进去的。

DinosaurRegistry使用返回null来表示get()查询某个恐龙没有发现,任何调用必须同意这个空值约定,也就是,空值代表恐龙没有发现;或数据库没有查询到该数据。

DinosaurLab是将含义共生跨组件实现了,因为它与DinosaurEgg 和 DinosaurRegistry交互,这样也就同意了null值的约定含义。但是这会导致一系列逻辑含混不清甚至矛盾的情况。

如何避免含义共生?
引入类型,比如第一个案例中数字1代表食肉动物,2代表食草动物,我们可以使用Diet类型(使用枚举):


public enum Diet {
HERBIVOROUS, CARNIVOROUS
}
public class Dinosaur {
private Diet diet;
public Dinosaur(Diet diet) {
this.diet = diet;
}
public void feed(Food food) {
// Eat the food
}
public Diet getDiet() {
return diet;
}
}
public class DinosaurHandler {
private Dinosaur dinosaur;
public DinosaurHandler(Dinosaur dinosaur) {
this.dinosaur = dinosaur;
}
public void feedDinosaur() {
switch (dinosaur.getDiet()) {
case CARNIVOROUS:
dinosaur.feed(new Goat());
break;
case HERBIVOROUS:
dinosaur.feed(new Cabbage());
break;
}
}
}

在第二个案例中,移除所有各种约定,不再使用基于空值null的约定含义,通过抛出Exception来替代,或者引入新方法。


public class DinosaurEgg {
private static final long TEN_MINUTES = 600000;
private Date timeLaid;
public Date getTimeLaid() {
return timeLaid;
}
public boolean isReadyToHatch() {
return System.currentTimeMillis() - timeLaid.getTime() > TEN_MINUTES;
}
public Dinosaur hatch() {
if (isReadyToHatch()) {
return new Dinosaur(this);
} else {
throw new EggNotReadyToHatchException();
}
}
}

public class DinosaurRegistry {
public boolean isNameAvailable(String name) {
// Check the required name is available
}
public Dinosaur get(String name) {
// Get dinosaur with this name
// throw DinosaurNotFoundException if no dinosaur with name exists
}
public void register(Dinosaur dinosaur) {
// Register a dinosaur
// Name must be unique
}
}
public class DinosaurRegistry {
public boolean isNameAvailable(String name) {
// Check the required name is available
}
public Dinosaur get(String name) {
// Get dinosaur with this name
// throw DinosaurNotFoundException if no dinosaur with name exists
}
public void register(Dinosaur dinosaur) {
// Register a dinosaur
// Name must be unique
}
}
public class DinosaurRegistry {
public boolean isNameAvailable(String name) {
// Check the required name is available
}
public Dinosaur get(String name) {
// Get dinosaur with this name
// throw DinosaurNotFoundException if no dinosaur with name exists
}
public void register(Dinosaur dinosaur) {
// Register a dinosaur
// Name must be unique
}
}

Connascence of Meaning in Java - DZone Java

[该贴被banq于2016-08-12 17:38修改过]
[该贴被banq于2016-08-12 17:39修改过]