在开始阅读之前我先解释一下混型这个单词的具体含义:混合多个类的能力以产生一个可以表示混型中所有类型的类
与接口的混型
直接看下面的代码:
import java.util.*;
interface TimeStamped
{
long getStamp();
}
class TimeStampedImp implements TimeStamped
{
private final long timeStamp;
public TimeStampedImp()
{
timeStamp = new Date().getTime();
}
public long getStamp()
{
return timeStamp;
}
}
interface SerialNumbered {long getSerialNumber();}
class SerialNumberedImp implements SerialNumbered
{
private static long counter = 1;
private final long serialNumber = counter++;
public long getSerialNumber()
{
return serialNumber;
}
}
interface Basic
{
public void set(String val);
public String get();
}
class BasicImp implements Basic
{
private String value;
public void set(String val)
{
value = val;
}
public String get()
{
return value;
}
}
class Mixin extends BasicImp
implements TimeStamped, SerialNumbered
{
private TimeStamped timeStamp = new TimeStampedImp();
private SerialNumbered serialNumber = new SerialNumberedImp();
public long getStamp(){
return timeStamp.getStamp();
}
public long getSerialNumber(){
return serialNumber.getSerialNumber();
}
}
public class Mixins
{
public static void main(String[] args)
{
Mixin mixin1 = new Mixin();
Mixin mixin2 = new Mixin();
mixin1.set("test String 1");
mixin2.set("test String 2");
System.out.println(mixin1.get() + " " + mixin1.getStamp() + " " +mixin1.getSerialNumber());
System.out.println(mixin2.get() + " " + mixin2.getStamp() + " " +mixin2.getSerialNumber());
}
}
上面代码中Mixin类通过TimeStamped, SerialNumbered两个接口封装了其对应的TimeStampedImp, SerialNumberedImp两个子类。这就是通过了接口实现混型,但是可以预见,如果实现更复杂的混型,将会导致代码量急速增加,因为没要封装一种类型,就需要多定义一种接口,多实现以一种子类。
使用装饰器模型
先用代码演示一下什么叫做装饰器:
import java.util.*;
class Basic
{
private String value;
public void set(String val) {
value = val;
}
public String get(){
return value;
}
}
class Decorator extends Basic
{
private Basic basic;
public Decorator(Basic basic){
this.basic = basic;
}
public void set(String val){
basic.set(val);
}
public String get(){
return basic.get();
}
}
class TimeStamped extends Decorator
{
private final long timeStamp;
public TimeStamped(Basic basic){
super(basic);
timeStamp = new Date().getTime();
}
public long getStamp(){
return timeStamp;
}
}
class SerialNumbered extends Decorator
{
private static long counter = 1;
private final long serialNumber = counter++;
public SerialNumbered(Basic basic){
super(basic);
}
public long getSerialNumber(){
return serialNumber;
}
}
public class Decoration
{
public static void main(String[] args)
{
TimeStamped t = new TimeStamped(new Basic());
TimeStamped t2 = new TimeStamped(new SerialNumbered(new Basic()));
//t2.getSerialNumber();
t2.getStamp();
//t2并不存在getSerialNumber()这个用法
SerialNumbered s = new SerialNumbered(new Basic());
SerialNumbered s2 = new SerialNumbered(new TimeStamped(new Basic()));
//s2.getStamp();
//s2并不存在getStamp()这个用法
s2.getSerialNumber();
}
}
t2包装了SerialNumbered和Basic类但是实际上只有最后被装饰的类型也就是TimeStamped的类型的所有方法是可见的,所以SerialNumbered类的getSerialNumber()方法不可用,但是TimeStamped类的getStamp()方法是可用的,同理于s2,装饰器模型不同于继承所以也并不存在方法的继承或者重载。
与动态代理混合
想讲清楚这个问题,我们先复习一下代理的概念,欢迎大家看我另一篇针对代理和动态代理的博文:http://blog.csdn.net/weixin_40134367/article/details/77996937。
下面直接上代码解释什么叫做与动态代理的混合:
import java.lang.reflect.*;
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Tuple.*;
interface Basic
{
public void set(String val);
public String get();
}
class BasicImp implements Basic
{
private String value;
public void set(String val)
{
value = val;
}
public String get()
{
return value;
}
}
interface TimeStamped
{
long getStamp();
}
class TimeStampedImp implements TimeStamped
{
private final long timeStamp;
public TimeStampedImp()
{
timeStamp = new Date().getTime();
}
public long getStamp()
{
return timeStamp;
}
}
interface SerialNumbered {long getSerialNumber();}
class SerialNumberedImp implements SerialNumbered
{
private static long counter = 1;
private final long serialNumber = counter++;
public long getSerialNumber()
{
return serialNumber;
}
}
class MixinProxy implements InvocationHandler
{
Map<String,Object> delegatesByMethod;
//建用于保存方法名称,值用于保存对象
public MixinProxy(TwoTuple<Object, Class<?>>... pairs){
delegatesByMethod = new HashMap<String,Object>();
for(TwoTuple<Object, Class<?>> pair : pairs){
for(Method method : pair.second.getMethods()){
//pair.second保存的是对象的类
String methodName = method.getName();
if(!delegatesByMethod.containsKey(methodName)){
delegatesByMethod.put(methodName, pair.first);
//pair保存的是对象
}
}
}
}
public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{
String methodName = method.getName();
Object delegate = delegatesByMethod.get(methodName);
return method.invoke(delegate, args);
}
@SuppressWarnings("unchecked")
public static Object newInstance(TwoTuple...pairs){
Class[] interfaces = new Class[pairs.length];
for(int i=0; i<pairs.length; i++){
interfaces[i] = (Class)pairs[i].second;
}
ClassLoader cl = pairs[0].first.getClass().getClassLoader();
return Proxy.newProxyInstance(cl, interfaces, new MixinProxy(pairs));
}
}
public class DynamicProxyMixin{
public static void main(String[] args){
Object mixin = MixinProxy.newInstance(
tuple(new BasicImp(), Basic.class),
tuple(new TimeStampedImp(),TimeStamped.class),
tuple(new SerialNumberedImp(),SerialNumbered.class));
//在对应类型上调用方法之前,必须显式的将其向下转型,所以还称不上是真正的混型
Basic b = (Basic)mixin;
TimeStamped t = (TimeStamped)mixin;
SerialNumbered s = (SerialNumbered)mixin;
b.set("Hello");
System.out.println(b.get());
System.out.println(t.getStamp());
System.out.println(s.getSerialNumber());
}
}
简单的介绍一下这个代码是怎么通过动态代理实现混型的:主要是基于动态代理是通过另外一层的方法调用而不是在直接在被代理对象上进行方法调用,我们将想要混型的类和对应的方法放在一个Map容器中,然后我们就可以在实现InvocationHandler接口的invoke方法时,得到想要实现的方法名,然后再通过方法名获取在Map容器中对应的类,在invoke的返回参数中将Proxy代理换成对应的类,就可以模拟混型。需要注意的是,我们这种方式相当于必须找出方法所对应的类,所以我们所有混型的类不能有重名的方法。