动态代理模式案例(代码)讲解

设计模式的代码:https://github.com/Aerozb/design_patterns

目录

需求

静态代理实现

动态代理实现

查看代理类的结构

需求

如上图,张三及其跟他有关系的人需要购买A,B公司的产品 ,比如张三向A公司买女性娃娃,张三老婆向B公司买男性娃娃;

但是因为在海外,所以只能向代购公司购买,而且代购公司还能提供购买前后的服务,比如买前咨询,买后问怎么用。

静态代理实现

1.卖男性娃娃的工厂

public interface IManFactory {
	// 卖男性娃娃
	public void saleMan(float length);
}
public class ManFactory implements IManFactory {
	@Override
	public void saleMan(float length) {
		System.out.println("男性" + length);
	}
}

2.卖女性娃娃的工厂

public interface IWomanFactory {
	// 卖女性娃娃
	public void saleWoman(int faceSource);
}
public class WomanFactory implements IWomanFactory {
	@Override
	public void saleWoman(int faceSource) {
		System.out.println("女性" + faceSource);
	}
}

3.中间海外代理商

/**
 * 代理商
 */
public class LisonCompany implements IManFactory, IWomanFactory {
    private IManFactory manFactory;
    private IWomanFactory womanFactory;

    public void setManFactory(IManFactory manFactory) {
        this.manFactory = manFactory;
    }

    public void setWomanFactory(IWomanFactory womanFactory) {
        this.womanFactory = womanFactory;
    }

    @Override
    public void saleMan(float length) {
        before();
        manFactory.saleMan(length);
        after();
    }

    @Override
    public void saleWoman(int faceSource) {
        before();
        womanFactory.saleWoman(faceSource);
        after();
    }

    public void before() {
        System.out.println("售前服务");
    }

    public void after() {
        System.out.println("售后服务");
    }
}

4.测试

public class Test {
	public static void main(String[] args) {
		// 男性工厂
		IManFactory manFactory = new ManFactory();
		// 女性工厂
		IWomanFactory womanFactory = new WomanFactory();
		// 中间商
		LisonCompany company = new LisonCompany();

		// 中间代理商设置男性工厂
		company.setManFactory(manFactory);
		// 女客户开始购买男性娃娃,由中间商调用代理过后的方法
		company.saleMan(18);

		System.out.println("====================");

		// 中间代理商设置男性工厂
		company.setWomanFactory(womanFactory);
		// 男客户开始购买男性娃娃,由中间商调用代理过后的方法
		company.saleWoman(10);
	}
}

 5.结果

售前服务
男性18.0
售后服务
====================
售前服务
女性10
售后服务

可以看出如果是静态代理实现,中间商需要实现并聚合XX工厂,如果客户不仅要购买娃娃,还要购买洗面奶等物品,这时候又要实现并继承,然后实现其方法进行代理,如果只增加一个工厂还好,但是客户买的越来越多 不同产品,中间商就需要代理更多工厂,这样中间商的代码就越来越庞大,并不符合单一,开闭的设计原则,所有解决办法就是用动态代理。

动态代理实现

1.卖男性娃娃的工厂

public interface IManFactory {
	// 卖男性娃娃
	public void saleMan(float length);
}
public class ManFactory implements IManFactory {
	@Override
	public void saleMan(float length) {
		System.out.println("男性" + length);
	}
}

2.卖女性娃娃的工厂

public interface IWomanFactory {
	// 卖女性娃娃
	public void saleWoman(int faceSource);
}
public class WomanFactory implements IWomanFactory {
	@Override
	public void saleWoman(int faceSource) {
		System.out.println("女性" + faceSource);
	}
}

3.中间海外代理商

/**
 * 代理商
 */
public class LisonCompany implements InvocationHandler {

	// 聚合工厂,客户需要哪个工厂生产的产品就设置哪个工厂
	private Object factory;

	public void setFactory(Object factory) {
		this.factory = factory;
	}

	// 返回一个代理过后的工厂
	public Object getProxyInstance() {
		return Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), this);
	}

	@Override
	public Object invoke(Object o, Method method, Object[] params) throws Throwable {
		before();
		// 反射调用方法
		Object result = method.invoke(factory, params);
		after();
		return result;
	}

	public void before() {
		System.out.println("售前服务");
	}

	public void after() {
		System.out.println("售后服务");
	}
}

4.测试

public class Test {
	public static void main(String[] args) {
		// 男性工厂
		IManFactory manFactory = new ManFactory();
		// 女性工厂
		IWomanFactory womanFactory = new WomanFactory();
		// 中间商
		LisonCompany company = new LisonCompany();

		// 中间代理商设置男性工厂
		company.setFactory(manFactory);
		// 生成代理对象,代理商可在买卖前后做一些操作
		IManFactory manFactoryProxy = (IManFactory) company.getProxyInstance();
		//  女客户开始购买男性娃娃,从代码来看,似乎是客户直接向工厂够买,其实是由中间商调用代理过后的方法。
		manFactoryProxy.saleMan(80);

		System.out.println("====================");

		// 中间代理商设置女性工厂
		company.setFactory(womanFactory);
		// 生成代理对象,代理商可在买卖前后做一些操作
		IWomanFactory womanFactoryProxy = (IWomanFactory) company.getProxyInstance();
		// 调用代理过后的方法
		womanFactoryProxy.saleWoman(6);
	}
}

5.结果

售前服务
男性80.0
售后服务
====================
售前服务
女性6
售后服务

可以看到,动态代理模式符合开闭原则,无需再原来的类(代理商)上修改,只需增加新的接口及其实现类就行,比静态代理简洁方便。

如果顾客需要新的海外产品,比如,洗面奶,只需要在新增一个洗面奶工厂类就行,中间商无需在修改,然后用户购买时,只需new出来新的工厂,中间商在设置进去就行;符合开闭原则的对外开发拓展,对内关闭修改原则。

查看代理类的结构

我们的代理类是生成在jvm内存中,所以需要把内存中的字节码文件转成class保存到硬盘,我们才能查看。

透过源码确实可以看出是在这生成的,那我们也用类似的方法,生成出我们要的代理类。

/**
 * 将jvm内存中的代理类输出到桌面
 */
public class ProxyUtil {
    public static void generator(Class clz, String name) {
        byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{clz});
        String path = FileSystemView.getFileSystemView().getHomeDirectory().getAbsolutePath() +File.separator+ name + ".class";
        System.out.println(path);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(new File(path));
            fos.write(bytes);
            fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

 我们就在上面的动态代理测试类中,末尾加上以下这两句,然后在运行,就可以在桌面看到两个代理文件。

                //将代理类生成class文件
		ProxyUtil.generator(manFactory.getClass(),manFactoryProxy.getClass().getSimpleName());
		ProxyUtil.generator(womanFactory.getClass(),womanFactoryProxy.getClass().getSimpleName());

将生成的class文件直接拖到 IDEA,就可以反编译查看了,忽略不重要的方法属性,可以看到确实有个同名方法,而他调用的就是我们实现InvocationHandler的类LisonCompany的invoke方法,其中h就是我们的LisonCompany,h就是在父类Proxy 中设置的。

public final class $Proxy0 extends Proxy implements ManFactory {

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final void saleMan(float var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值