类和接口 - 包装类

阅读更多
  继承固然非常强大,但我们不能滥用继承,如使用不当,则会引起诸多问题.只有当子类和超类之间确实存在"is-a"关系的时候,使用继承才是恰当的.即便如此,如果子类和超类在不同的包中,并且超类不是为了继承而设计的,那么继承将会是脆弱的.此时,我们应该考虑用包装类,一复合和转发机制来代替继承.
  让我们来看个具体的例子: 我们假设程序用了个HashSet, 我们想统计一个HashSet对象创建以来总共加了多少个元素,为了实现这个功能,我们首先考虑继承,然后覆盖原有的实现加个计数:
 package com.effective.item16;

import java.util.Collection;
import java.util.HashSet;

public class InstrumentedHashSet extends HashSet {

	private static final long serialVersionUID = 1L;
	
	private int count = 0;

	InstrumentedHashSet() {
		super();
	}
	
	@Override
	public boolean add(E e){
		count++;
		return super.add(e);
	}
	
	@Override
	public boolean addAll(Collection c){
		count += c.size();
		return super.addAll(c);
	}
	
	public int getCount(){
		return count;
	}
	
}


  结果发现但我们调用如下代码时,计数本应为3,真实结果为6. 什么原因呢? 原来父类HashSet里面addAll方法调用了add方法.这种内部细节,我们作为api的使用者很难知道,除非查看源码. 继而又有个严重的问题,如果HashSet的具体实现改变了,那么又有可能引起其他的问题,很难察觉.
  让我们换种思路,采用复合代替继承.

import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

public class WrapperSet implements Set {

	private int count = 0;
	private Set s;
	
	private WrapperSet(Set s) {
		super();
		this.s = s;
	}

	...

	@Override
	public boolean add(E e) {
		count++;
		return s.add(e);
	}

	@Override
	public boolean remove(Object o) {
		return s.remove(o);
	}

	@Override
	public boolean containsAll(Collection c) {
		return c.containsAll(c);
	}

	@Override
	public boolean addAll(Collection c) {
		if(c != null)
			count += c.size();
		return s.addAll(c);
	}
...
	
}


  Set接口保存了HashSet的功能特性,看似麻烦了些,但程序变得健壮了,这种Wrapper设计也带来了灵活性,他可以包装任何的Set实现, 同时又很好的扩展了计数器.
  关于包装类,大家可以结合Decorator模式和Proxy模式做更深入的研究.
 

你可能感兴趣的:(Java,Wrapper,类,接口,模式)