目录
使类和成员的可访问性最小化
在公有类中使用访问方法而非公有域
使可变性最小化
复合优先于继承
接口优于抽象类
抽象类的缺点
接口的优点
接口只用于定义类型
类层次优于标签类
用函数对象表示策略
优先考虑静态成员类
静态成员类和非静态成员类
使类和成员的可访问性最小化
当我们设计类的时候,应该将公共的api设置为共有的,而其它的实现调用类的访问修饰符(private、protected、public)则不应该是共有的,每一层调用的类只需要能让它的上一次访问即可,而不需要被其它无关的类访问到。
对于成员的访问修饰符(private、default、protected、public)尽可能的设置为private,而通过setter、getter来改变成员的属性。
在公有类中使用访问方法而非公有域
对于公有类,应该将成员设置为私有,并提供成员的访问方法
使可变性最小化
在定义一个类的时候,优先设置为final(不可变类),其次考虑该类是否需要设计为可变类
复合优先于继承
首先看一个继承的错误例子
通过继承HashSet类来覆盖add方法和addAll方法,重写这2个方法来实现插入元素的个数。
public class ObjExtendsHashSet extends HashSet<String>{
private int addCount;
public ObjExtendsHashSet() {
}
public ObjExtendsHashSet(int initcap,float loadFactor){
super(initcap, loadFactor);
}
@Override
public boolean add(String e) {
addCount++;
return super.add(e);
}
@Override
public boolean addAll(Collection<? extends String> c) {
addCount += c.size();
return super.addAll(c);
}
public int getAddCount() {
return addCount;
}
public static void main(String[] args) {
ObjExtendsHashSet set = new ObjExtendsHashSet();
set.addAll(Arrays.asList("1","2","3"));
System.out.println(set.getAddCount());//打印6
}
}
上面这段代码打印的值为6,而并非是我们预想的值3,下面来解答一下为什么打印值是6,由于addAll方法是基于add方法实现的,所以每次调用addAll方法时,会循环遍历lis集合调用add方法,所以一共执行了1次addAll方法和3次add方法。
在AbstractCollection抽象类中addAll方法的接口文档已经告诉我们addAll方法会遍历集合并依次调用add方法:
/**
* {@inheritDoc}
*
* <p>This implementation iterates over the specified collection, and adds
* each object returned by the iterator to this collection, in turn.
*
* <p>Note that this implementation will throw an
* <tt>UnsupportedOperationException</tt> unless <tt>add</tt> is
* overridden (assuming the specified collection is non-empty).
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @throws IllegalStateException {@inheritDoc}
*
* @see #add(Object)
*/
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
Iterator<? extends E> e = c.iterator();
while (e.hasNext()) {
if (add(e.next()))
modified = true;
}
return modified;
}
那么为了解决继承过于强大的问题,引出复合和转发的概念。
不扩展现有的类,而是在新的类中增加一个私有域(成员变量),新的类引用这个现有类的一个实例,这叫做复合。
新类中的每个实例方法都可以调用被包含的现有类的实例中的对应方法,并返回它的结果,这叫做转发。
运用复合+转发的方式可以实现list集合统计增加的元素数。
转发类(复合类:将现有类作为新类的一个组件):
public class ForwardingSet implements Set<String>{
private Set<String> s;
public ForwardingSet(Set<String> s){
this.s = s;
}
@Override
public int size() {
return s.size();
}
@Override
public boolean isEmpty() {
return s.isEmpty();
}
@Override
public boolean contains(Object o) {
return s.contains(o);
}
@Override
public Iterator<String> iterator() {
return s.iterator();
}
@Override
public Object[] toArray() {
return s.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return s.toArray(a);
}
@Override
public boolean add(String e) {
return s.add(e);
}
@Override
public boolean remove(Object o) {
return s.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return s.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends String> c) {
return s.addAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return s.retainAll(c);
}
@Override
public boolean removeAll(Collection<?> c) {
return s.removeAll(c);
}
@Override
public void clear() {
s.clear();
}
}
继承类:
public class ObjImpSet extends ForwardingSet{
private int addCount;
public ObjImpSet(Set<String> s) {
super(s);
}
@Override
public boolean add(String e) {
addCount++;
return super.add(e);
}
@Override
public boolean addAll(Collection<? extends String> c) {
addCount+=c.size();
return super.addAll(c);
}
public int getAddCount() {
return addCount;
}
public static void main(String[] args) {
ObjImpSet objImpSet = new ObjImpSet(new HashSet<String>());
objImpSet.addAll(Arrays.asList("1","2","3"));
System.out.println(objImpSet.getAddCount());
}
}
接口优于抽象类
抽象类的缺点
1.只能单继承
2.继承抽象类有层级限制
3.灵活性差
接口的优点
1.类可以实现多个接口
2.不受层级限制的影响
3.可扩展,灵活性强
接口只用于定义类型
简而言之,接口定义了一组抽象方法,它可以作为实现该接口的类实例的引用,其他的用处都是不恰当的。
类层次优于标签类
参考工厂模式
用函数对象表示策略
参考策略模式
优先考虑静态成员类
嵌套类是被定义在类内部的类,并未外部类提供服务。嵌套类可以分为静态成员类、非静态成员类、匿名类、局部类4种。
静态成员类和非静态成员类的区别就是是否用static修饰,匿名类,顾名思义就是没有名字的类,局部类是指在任何可以声明局部变量的地方都可以申明局部类。
静态成员类和非静态成员类
如果声明成员类不需要访问外围实例,那么就要使用静态成员类,如果缺少static修饰符,那么这个成员类必须要指向外围类的引用,保存这个引用需要消耗时间和空间,并且会导致外围类符合垃圾回收机制却不能被回收。如果没有外围实例就不能使用非静态成员类。