含义共生性(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修改过]