private Observable observable = new Observable();
public synchronized void addObserver(Observer o) {
observable.addObserver(o);
}
public synchronized void deleteObserver(Observer o) {
observable.deleteObserver(o);
}
public void notifyObservers() {
observable.notifyObservers();
}
public void notifyObservers(Object arg) {
observable.notifyObservers(arg);
}
public synchronized void deleteObservers() {
observable.deleteObservers();
}
protected synchronized void setChanged() {
observable.setChanged();
}
protected synchronized void clearChanged() {
observable.clearChanged();
}
public synchronized boolean hasChanged() {
return observable.hasChanged();
}
public synchronized int countObservers() {
return observable.countObservers();
}
}
这下好了,现在我们的User,Person,Employee要是想具有可被观察的功能,那就改去继承我们适配好的BaseObservableEntity就好了,而且由于BaseObservableEntity继承了BaseEntity,所以他们三个依然处于我们实体的继承体系中,而且由于我们的BaseObservableEntity是新增的扩展基类,所以不会对原来的继承体系造成破坏。
适配器模式的用法还是比较清晰的,我们以上两种方式都是为了复用现有的代码而采用的适配器模式,LZ刚才说了,根据目的的不同,适配器模式也可以分为两种,那么上述便是第一种,还有另外一种称为缺省适配器。
首先我们得先说下缺省适配器为什么要出现,因为适配器模式大部分情况下是为了补救,所以既然补救,那么肯定是历史原因造成的我们需要使用这个模式。
我们来看看缺省适配器的历史来由,不知各位还是否记得在第一章总纲中,LZ曾经提到过一个原则,最小接口原则。
这个原则所表达的思想是说接口的行为应该尽量的少,那么还记得LZ当时说如果你没做到的话会产生什么情况吗?
结果就是实现这个接口的子类,很可能出现很多方法是空着的情况,因为你的接口设计的过大,导致接口中原本不该出现的方法出现了,结果现在子类根本用不上这个方法,但由于JAVA语言规则的原因,实现一个接口必须实现它的全部方法,所以我们的子类不得不被迫写一堆空方法在那,只为了编译通过。
所以为了解决这一问题,缺省适配器就出现了。比如我们有如下接口。
[java]
public interface Person {
void speak();
void listen();
void work();
}
public interface Person {
void speak();
void listen();
void work();
} 这是一个人的接口,这个接口表示了人可以说话,听和工作,假设是两年前的LZ,还在家待业呢,LZ没工作啊,但是LZ也是个人啊,所以LZ要实现这个接口,所以LZ只能把work方法抄下来空着放在那了,假设LZ是个聋哑人,好吧,三个方法都要空着了,但是LZ表示,LZ是人,LZ一定要实现Person接口。
当然,上述只是举个例子,但是真实项目当中也会出现类似的情况,那么怎么办呢?
这下来了,我们的缺省适配器来了,如下。
[java]
public class DefaultPerson implements Person{
public void speak() {
}
public void listen() {
}
public void work() {
}
}
public class DefaultPerson implements Person{
public void speak() {
}
public void listen() {
}
public void work() {
}
} 我们创造一个Person接口的默认实现,它里面都是一些默认的方法,当然这里因为没什么可写的就空着了,实际当中可能会加入一些默认情况下的操作,比如如果方法返回结果整数,那么我们在缺省适配器中可以默认返回个0。
这下好了,LZ只要继承这个默认的适配器(DefaultPerson),然后覆盖掉LZ感兴趣的方法就行了,比如speak和listen,至于work,由于适配器帮我们提供了默认的实现,所以就不需要再写了。
这种情况其实蛮多的,因为接口设计的最小化只是理想状态,难免会有一些实现类,对其中某些方法不感兴趣,这时候,如果方法过多,子类也很多,并且子类的大部分方法都是空着的,那么就可以采取这种方式了。
当然,这样做违背了里氏替换原则,但是上面的做法原本就违背了接口的最小化原则,所以我们在真正使用时要权衡二者的利弊,到底我们需要的是什么。所以从此也可以看出来,原则只是指导,并不一定也不可能全部满足,所以我们一定要学会取舍。
总结下两种实现方式的适配器所使用的场景,两者都是为了将已有类的代码复用并且适配到客户端需要的接口上去。
1,第一种类适配器,一般是针对适配目标是接口的情况下使用。
2,第二种对象适配器,一般是针对适配目标是类或者是需要复用的对象多于一个的时候使用,这里再专门提示一下,对象适配器有时候是为了将多个类一起适配,所以才不得不使用组合的方式,而且我们采用对象适配器的时候,继承也不是必须的,而是根据实际的类之间的关系来进行处理,上述例子当中一定要直接或间接的继承自BaseEntity是为了不破坏我们原来的继承体系,但有些情况下这并不是必须的。