在實際開發中,我們往往需要對某些方法進行增強,常用的方法增強的方式有三種,下面就簡單介紹一下三種方式的使用以及特點
需求:
有一個Animal接口,提供了抽象方法eat(),有一個貓類實作了Animal接口,重寫了eat方法
class Animal {
public void eat();
}
class Cat implements Animal{
@Override
public void eat() {
System.out.println("吃老鼠");
}
}
class Test {
public static void main(String[] args) {
handleMouse(new Cat());
}
public static handleMouse(Animal animal) {
animal.eat();
}
}
運作程式:
吃老鼠
要求對Cat類中eat方法進行增強(吃老鼠之前抓老鼠)
1.解決方案一:繼承
建立一個類SuperCat繼承Cat,對eat方法進行重寫
class SuperCat extends Cat {
@Override
public void eat(){
System.out.println("抓老鼠");
super.eat();
}
}
//測試
class Test {
public static void main(String[] args) {
handleMouse(new SuperCat());
}
public static handleMouse(Animal animal) {
animal.eat();
}
}
運作程式:
抓老鼠
吃老鼠
這種方法的前提是能夠控制被增強方法的類的構造,而在面向接口程式設計中, 往往不能明确實作類,比如jdbc連接配接池需要對Connection的close方法進行增強,将關閉連接配接改為歸還連接配接,而Connection的實作類并不能确定(由各廠商提供),是以繼承的方式不能滿足這種需求
2.解決方案二:裝飾者設計模式
建立一個類SuperCat實作Animal接口,将animal作為其一個成員屬性,對eat方法進行重寫
public class SuperCat implements Animal {
Animal animal;
public SuperCat(Animal animal) {
this.animal = animal;
}
@Override
public void eat() {
System.out.println("抓老鼠");
animal.eat();
}
}
//測試
public class Test {
public static void main(String[] args) {
handleMouse(new SuperCat(new Cat()));
}
public static handleMouse(Animal animal) {
animal.eat();
}
}
運作程式:
抓老鼠
吃老鼠
這種方法要求裝飾類與被裝飾類要實作同一個接口,如果接口的方法比較多,而隻需要對其中一個方法進行增強,則接口中的其他方法需要提供空實作,常用的一個解決方案是定義一個類實作該接口,并提供所有方法的空實作,裝飾類若要增強其中一個方法隻需繼承這個空實作類,并重寫相應的方法,如可以對上面解決方案進行改寫
//定義一個Animal的空實作類
public class AnimalWrapper implement Animal{
Animal animal;
public AnimalWrapper(Animal animal) {
this.animal = animal;
}
public void eat() {
}
}
//定義SuperCat類
public class extends AnimalWrapper{
public AnimalWrapper(Animal animal) {
super(animal);
}
public void eat() {
System.out.println("抓老鼠");
animal.eat():
}
}
經典應用場景:web開發中,需要對HttpServletRequest的getParameter(String args)方法進行增強(處理get方式亂碼),HttpServletRequest提供了一個HttpServletRequestWrapper類,我們可以繼承這個空實作類對getParameter(String args)進行增強
3.解決方案三:動态代理
public class Test {
public static void main(String[] args) {
Cat cat = new Cat();
Animal proxyInstance = (Animal)Proxy.newProxyInstance(cat.getClass().getClassLoader(), cat.getClass().getInterfaces(), new InvocationHandler() {
//每次調用代理對象的任意方法,invoke方法就執行了
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//需要增強的方法
if("eat".equals(method.getName())) {
System.out.println("抓老鼠");
method.invoke(cat);
return null;
}
//不需要增強的方法
return method.invoke(cat);
}
});
handleMouse(proxyInstance);
}
public static void handleMouse(Animal animal) {
animal.eat();
}
}
運作程式:
抓老鼠
吃老鼠
這種方式比較靈活,隻需要被代理類有實作的接口就行