1.使类和成员的可访问性最小化
a.封装(数据私有化,方法公开化)/对外提供可调用的,稳定的功能
b.可访问性应该明确
修饰符 | 本类 | 同包类 | 子类 | 其他类 |
public | √ | √ | √ | √ |
protected | √ | √ | √ | |
默认 | √ | √ | ||
private | √ |
c.实例域绝不能是公有的
d.例子
- FieldPublicTest
- Point/Dimension
e.包级私有的顶级类只在某一个类内部被用到,就可以使用成为它的嵌套类
2.使可变性最小化(不可变对象)
a.遵循规则
1. 不要提供任何会修改对象状态的方法
2. 保证类不会被扩展
3. 所有域都要是final,且为私有
4. 确保对于任何可变组件的互斥访问。
b.优点
1. 线程安全
不可变对象是线程安全的,在线程之间可以相互共享,不需要利用特殊机制来保证同步问题,因为对象的值无法改变。
2. 易于构造、使用和测试
不可变对象为其他对象提供了大量的构件
c.缺点
1. 需要为每一个不同的值提供不同的对象。如果创建的对象比较大,那么所产生的代价就有点高了
2. String -> StringBuilder(可变配套类)
d.总结
1. 坚决不要为每个get方法编写一个相应的set方法
e.例子
-- ComplexTest
3.复合优先于继承
a.原因
1. 继承打破了封装性。子类信赖于其超类中特定功能的实现细节。超类的实现有可能会随着发行版本的不同而有变化,子类有可能会被破坏
Stack/
b.复合优点
1. 不破坏封装,整体类与局部类之间松耦合,彼此相对独立
2. 具有较好的可扩展性
3. 支持动态组合。在运行时,整体对象可以选择不同类型的局部对象
4. 整体类可以对局部类进行包装,封装局部类的接口,提供新的接口
c.复合缺点
1. 整体类不能自动获得和局部类同样的接口
2. 创建整体类的对象时,需要创建所有局部类的对象
d.总结
1. 只有当子类和父类确实存在子类型关系时,使用继承才是恰当的
2. 继承会把父类所有的缺陷继承过来
3. 复合是has a, 继承是is a。
e.例子
-- ForwardTest
4.要么为继承而设计,提供文档说明,要么禁止继承
a. 注意父类中各方法之间的相互调用,特别是可被覆盖的方法。一定要在文档中说明其自用性。(Interator的remove方法)
b. 类必须提供适当的钩子,以便能进入到它的内部工作流程中。可以是受保护的方法,也可以是受保护的域。(AbstractList的removeRange)
c. 对于为了继承而设计的类,唯一的测试方法就是编写子类。经验表明,三个子类通常可以测试一个可扩展的类。
d. 构造器、静态工厂方法和其他具有构造对象功能的方法决不能调用可被覆盖的方法(例子:)
e. 为了继承而设计类的时候,Cloneable和Serializable接口出现了特殊的困难。(readResolve应是受保护的方法)
f. 通过完全消除类中的可覆盖方法的自用特性,也可以创建”能够安全地进行子类化“的类。(文档说明/不会调用可覆盖的方法)
5.接口优先于抽象类
a.优点
1. 现有类可以很容易的实现更新,通过实现新的接口
2. 接口是定义混合类型的理想选择
3. 接口允许我们构造非层次结构的类型框架
1 public interface Songer{ 2 void song(); 3 } 4 public interface SongWriter{ 5 Song writeSong(); 6 } 7 pulbic interface SongerWriter extends Songer,SongWrite{ 8 void act(); 9 }
b.缺点
1. 在版本演变中很难通过新添加接口方法进行功能添加,但是抽象类可以很轻松搞定这种事
c.总结
1. 当演变的容易性比比灵活性和功能性更为重要时,应该用抽象类定义类型
6.接口只用于定义类型
a. 常量接口模式是对接口的不良使用。
b. 会导致使用者对接口含义的模糊,而且使用选择了实现该接口,那么后续不在需要这些常量的时候,我们不能删除该接口。(二进制兼容性)
1 public interface EarthConstants{ 2 double EARTH_RADIUS = XXXXX.XXXXX; 3 } 4 5 public final class EarthConstants{ 6 private EarthConstants(){} 7 public static final double EARTH_RADIUS = XXXXX.XXXXX; 8 }
7.类层次优先于标签类
a. 标签类过于冗长、容易出错,并且效率低下。
b. 类层次逻辑清晰,便于维护
8.用函数对象表示策略
a. 利用对象引用实现函数指针的功能,可以实现策略模式。
9.优先考虑静态成员类
a.原因
1.非静态成员类的每个实例都隐含着与外围类的一个外围实例想关联。在其被创建时,关联关系也建立了,这个关系不能被修改了。
b.优点
1. 内部类包括:成员类、局部类、匿名类。
2. 静态类不能访问外部类的非静态成员和非静态方法(不管是public还是private的);
3. 静态类的实例不需要先实例化外部类成员,可直接实例化。
c.成员类、局部类、匿名类
-- 成员类
0. 从技术上来说,可以分为两种:成员内部类和成员嵌套类。
1. 成员内部类即这里说的成员类,全称是非静态成员内部类
2. 成员嵌套类即上面的静态嵌套类
3. 可以直接调用外部类的方法
4. 定义一个Adapter,他允许外部类的实例被看作是另一个不相关的类的实例(Map中的KeySet、entrySet)
1 public class Main{ 2 public class MemberClass{}//成员内部类,常简称为成员类 3 }
-- 局部类
1. 任何可以声明局部变量的地方都可声明局部类
2. 只有在非静态环境中使用才会与外部类实例关联
3. 注意到了吧,可以同名,编译后,形成诸如:外部类名称+$+同名顺序+局部类名称(Test$1AA.class/Test$2AA.class/Test$3AA.class)
public class Test { { class AA{ // 块内局部类 } } public Test(){ class AA{ // 构造器内局部类 } } public static void main(String[] args){ } public void test(){ class AA{ // 方法内局部类 } } }
-- 匿名类(成员匿名类/局部匿名类)
1. 没有类名,不能使用继承,实现接口等特性
2. 只有在使用的时候才会初始化,并与外部类实例建立联系
3. 可以出现在代码中的任何允许表达式出现地方
4. 必须保持简短才能保证程序良好的阅读性
5. 常见使用:创建对象过程:Thead、Runnable,静态工厂方法内部
public class Test { InterfaceA a = new InterfaceA() { //成员匿名类 }; public static void main(String[] args){ InterfaceA a = new InterfaceA() { //局部匿名类 }; // 以上两种是通过实现接口实现匿名类,称为接口式匿名类,也可以通过继承类 Test test = new Test(){}; //继承式匿名类 // 还可以是位于参数上 new Thread(new Runnable() { @Override public void run() { } }).start();// 属于局部匿名类一种 } private interface InterfaceA{ } }
d.总结
1. 成员类:位于类内部但不包括位于块、构造器、方法内,且有名称的类。
2. 局部类:位于块、构造器、方法内的有名称类。
3. 匿名类:类内无名称类,又可细分为:成员匿名类和局部匿名类。