1. 类
每一个类其实就是这样一个声明:这些逻辑应该放在一起,它们的变化不像它们所操作的数据那么频繁;这些数据也应该放在一起,它们的变化频率差不多,并且由与之关联的逻辑来处理。因为一般数据的变化要比逻辑频繁得多,类的主要目的就是把逻辑与数据分离开来。学会如何用类来包装逻辑和如何表达逻辑的变化,这是有效使用对象编程的重要部分。
2.简单的超类名
找到一个贴切的名字是编程中最令人开心的时刻之一。在所有的命名中,类的名字最重要。类是维系其他概念的核心。一旦类有了名字,其中操作的名字也就顺理成章了。为了给一个类取一个简洁又有变现力的名字,需要给这个类要计算的逻辑找到一个强有力的隐喻。比如一个画图类DrawingObject,然后看到这个绘图对象的效果是画出来了一个图形(Figure)。于是这个画图类改成了名字Figure比原来那个名字更简洁也更有变现力。
3.限定性的子类名
子类的名字有两个重要职责,a.描述这些类像什么,b.他们之间的区别是什么。子类的命名应该尽量把这两个职责体现出来。
与他人沟通是类名的用途,如果仅仅只是为了跟计算机沟通,只要给每个类编号就足够了。如果一组类的名字体现不出它们之间的相关性,阅读者就很难对它们形成整体印象,也很难回忆起它们的关系。应该用类名来讲叙代码的故事。
4.接口与抽象类
在选择超类的时候,是选择接口还是选择抽象类取决于你今后是否需要对超类进行修改。如果非常有可能进行修改,那么使用抽象类,抽象类里面可以添加一个方法实现,所有继承于这个抽象类的类都能调用这个方法。而如果是接口的话,接口里面只能声明这个方法,那么所有实现这个接口的类都得去实现这个方法,非常的麻烦。但是如果超类定义之后不太可能修改,就可以用接口。(关键是看日后修改的难易程度,即使是日后很有可能修改,但是这个接口确定就只有一个实现类,也可以用接口的。)
5.值对象
java中有2种主要对象:
实体:在时间上有连续性,并且有唯一标识可以来区分的对象。
值对象:用来描述事物的,不区分谁是谁的,不可变的对象。
判断一个对象是实体还是值对象,还要根据它在具体的业务领域中的实际意义来决定,比如:
体育馆里的座位,当业务领域这样规定,一张门票对应一个特定的座位,即每个座位都应该严格区分谁是谁,观众在选择座位时根据门票对应的座位号来选择这个唯一的座位,此时座位对象应该为实体。
但当业务领域改变规则,决定只要有门票,就可以进去随便坐,此时不需要明确哪个座位是哪个座位,只要有座位就可以坐下,每个座位都是同一个座位对象的副本(在某些场合可以通过共享一个对象来提高性能),无须区分谁是谁,此时座位对象应该为值对象。
我们的程序在构建一个类的时候需要将“状态需要发生变化”与“对象不能变化”这两部分区分开来,分成不同类来对待,比如java里面的String类型是值对象。
6. 委派
要实现实例特有的行为,if/then和switch语句是最简单的方式。但是这样的做法是边判断边做处理。判断与处理混在一起,今后修改起来比较麻烦。还有一种实现方式叫做委派,先在外面进行判断,判断完了之后,传进来一个对象,调用这个对象的方法进行处理。这样就把判断与处理分开了,今后修改起来也方便。一个委派的例子:
public interface Idelegate {
public void test();
}
public class DelegateA implements Idelegate {
public void test() {
System.out.println("test A");
}
}
public class DelegateB implements Idelegate {
public void test() {
System.out.println("test B");
}
}
public class Delegate {
private Idelegate idelegate;
public Delegate(Idelegate idelegate) {
this.idelegate = idelegate;
}
public void test () {
idelegate.test();
}
}
public class TestMain {
public static void main(String[] args) {
Delegate d = new Delegate(new DelegateA());
d.test();
Delegate d2 = new Delegate(new DelegateB());
d2.test();
}
}
TestMain里面构造Delegate的时候传进去的参数是先做判断出来的结果,这个判断一般是一个方法,根据判断结果创建对应的实现类。