Java增強(qiáng)對(duì)象,無非是為了讓該對(duì)象具有更多的功能。Java增強(qiáng)對(duì)象主要有三種方式:繼承、裝飾者模式和動(dòng)態(tài)代理。
一、繼承
使得對(duì)象具有更多的功能,最最常用的方法就是繼承。子類繼承父類,便可擁有父類的屬性和方法。
特點(diǎn): 被增強(qiáng)的對(duì)象是固定的,增強(qiáng)的內(nèi)容也是固定的。
二、裝飾者模式
特點(diǎn):被增強(qiáng)的對(duì)象是可以更換的,但是增強(qiáng)的內(nèi)容是固定的。
裝飾者模式是指在不改變?cè)愇募凸δ艿那疤嵯拢瑒?dòng)態(tài)地?cái)U(kuò)展一個(gè)對(duì)象的功能。
In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern. The decorator pattern is structurally nearly identical to the chain of responsibility pattern, the difference being that in a chain of responsibility, exactly one of the classes handles the request, while for the decorator, all classes handle the request. --WIKIPEDIA
簡(jiǎn)而言之,就是將通用功能放在裝飾器中,在用到的時(shí)候進(jìn)行調(diào)用。 下面舉個(gè)例子:
1.定義一個(gè)接口
public interface interfaceA{
public void function();
}
2.定義一個(gè)實(shí)現(xiàn)類
public class classA implements interfaceA{
@Override
public void function(){
System.out.println("Here is in classA");
}
}
3.定義一個(gè)裝飾器
public class decorateA implement interfaceA{
//定義一個(gè)變量,來接收不同的增強(qiáng)對(duì)象
private interfaceA a;
public decorateA(interfaceA paramA){
this.a = paramA;
}
@Override public void function(){
System.out.println("在調(diào)用被增強(qiáng)對(duì)象的方法之前,干些事情");
a.function();
System.out.println("在調(diào)用被增強(qiáng)對(duì)象的方法之后,干些事情");
}
}
4.測(cè)試
public static void main(String [] args){
classA a = new classA();
a.function();
decorateA decorate = new decorateA(a);
decorate.function();
}
解釋:對(duì)于原來的類classA來說,并沒有改變?cè)擃惖膶傩院头椒?,只是將該類放在了decorateA【裝飾器】中后,增強(qiáng)了原來的類的方法和屬性。
三、動(dòng)態(tài)代理
動(dòng)態(tài)代理主要有jdk的動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理,這里主要說jdk動(dòng)態(tài)代理,cglib動(dòng)態(tài)代理將會(huì)在下一篇博客里面介紹。
動(dòng)態(tài)代理的特點(diǎn):被增強(qiáng)的對(duì)象可以改變,增強(qiáng)的內(nèi)容也可以改變。
首先我們來回顧一下動(dòng)態(tài)代理: jdk的動(dòng)態(tài)代理主要是由一個(gè)Proxy類的靜態(tài)方法newProxyInstance來實(shí)現(xiàn)的。
/** Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
該方法其實(shí)就是根據(jù)傳入的三個(gè)參數(shù)返回一個(gè)指定接口的代理類的實(shí)例。三個(gè)參數(shù)分別為:
- loader the class loader to define the proxy class【代理類的類加載器】
- interfaces the list of interfaces for the proxy class to implement【被代理對(duì)象所實(shí)現(xiàn)的接口】
-
h the invocation handler to dispatch method invocations to【調(diào)用處理程序】
其中InvocationHandler是一個(gè)接口,該接口下只有一個(gè)方法:
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
在進(jìn)行動(dòng)態(tài)代理的時(shí)候,需要重載invoke方法。invoke方法處理代理實(shí)例上的方法調(diào)用并返回結(jié)果。 在與其關(guān)聯(lián)的代理實(shí)例上調(diào)用方法時(shí),將在調(diào)用處理程序上調(diào)用此方法。
下面給出一個(gè)實(shí)例:
1.定義一個(gè)接口:
public interface Teacher{
public void teach();
}
2.定義兩個(gè)增強(qiáng)的接口
public interface First(){
public void first();
}
public interface Second(){
public void second();
}
3.定義一個(gè)代理工廠類,來生成代理對(duì)象
@Data
public class AgentFactory{
private Object target;
private First first;
private Second second;
public Object getProxyInstance(){
return Proxy.newProxyInstance(this.getClass.getClassLoader,
targer.getClass().getInterfaces(),
new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object [] args) throws Throwable{
//
if(first != null){
first.first();
}
if(second != null){
second.second();
}
return method.invoke(targer,args);
}
});
}
}
4.測(cè)試類
public static void main(String [] args){
AgentFactory factory = new AgentFactory();
factory.setTarger(new Teacher(){
@Override
public void teach(){
System.out.println("Teach");
}
});
factory.setFirst(new First(){
@Override
public void first(){
System.out.println("First");
}
});
factory.setSecond(new Second(){
@Override
public void second(){
System.out.println("Second");
}
});
Teacher teacher = (Teacher)factory.getProxyInstance();
teacher.teach();
}