在上一篇中咱们学习告终构型模式的组合模式和过滤器模式。本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式。html
简介java
享元模式主要用于减小建立对象的数量,以减小内存占用和提升性能。这种类型的设计模式属于结构型模式,它提供了减小对象数量从而改善应用所需的对象结构的方式。git
用通俗的话来讲就是进行共用。生活中也有一些例子,好比以前很火的共享单车,更早以前的图书馆,编程中常常用的String类,数据库链接池等等。固然,享元模式主要的目的是复用,若是该对象没有的话,就会进行建立。程序员
享元模式的角色主要分为三大类,抽象享元类、具体享元类以及享元工厂类。github
其它的就再也不多说,这里依旧使用一个简单的示例来加以说明。
在咱们之前读书的时候,常常会用到笔,其中铅笔又是最先接触的,咱们最开始使用铅笔可能不是写字,而是进行画画。这里咱们能够把笔看成一个抽象享元类,铅笔看成一个具体享元类,而后再建立一个享元工厂类,用于建立和管理,最后再由调用者决定用铅笔进行干吗。spring
首先,咱们建立一个接口。数据库
interface Pen { void write(); }
而后再建立一个享元工厂类,指定须要内部须要作的事情。编程
class Penil implements Pen { private String name; private String something; private int i; public Penil(String name) { this.name = name; i++; System.out.println(name+" 第:"+i+"次建立"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSomething() { return something; } public void setSomething(String something) { this.something = something; } @Override public void write() { System.out.println(name+" 用于铅笔 "+something); } }
继而再建立一个工厂类,用于建立和管理。设计模式
class PenFactory { private static final Map<String, Penil> map = new HashMap<String, Penil>(); public static Penil get(String name) { Penil penil = map.get(name); if (penil == null) { penil = new Penil(name); map.put(name, penil); } return penil; } }
最后再来进行调用测试。安全
public class FlyweightTest { public static void main(String[] args) { String names[] = { "张三", "李四", "王五", "虚无境" }; for (int i = 0; i < 8; i++) { Penil penil = PenFactory.get(names[i>3?i-4:i]); penil.setSomething("画了一条鱼"); penil.write(); } } }
输出结果:
张三 第:1次建立 张三 用于铅笔 画了一条鱼 李四 第:1次建立 李四 用于铅笔 画了一条鱼 王五 第:1次建立 王五 用于铅笔 画了一条鱼 虚无境 第:1次建立 虚无境 用于铅笔 画了一条鱼 张三 用于铅笔 画了一条鱼 李四 用于铅笔 画了一条鱼 王五 用于铅笔 画了一条鱼 虚无境 用于铅笔 画了一条鱼
上述示例中,每一个对象都使用了两次,可是每一个对象都只是建立了一次而已,而享元模式核心的目的其实就是复用,只要咱们理解了这一点,想必掌握该模式也就不在话下了。
享元模式优势:
极大的减小对象的建立,从而下降了系统的内存,提高了效率。
享元模式缺点:
提升了系统的复杂度,由于须要将状态进行分离成内部和外部,而且也使外部状态固有化,使得随着内部状态的变化而变化,会形成系统的混乱。
使用场景:
系统有大量类似对象。
注意事项:
须要注意划分外部状态和内部状态,不然可能会引发线程安全问题。 这些类必须有一个工厂对象加以控制。
与单例模式比较
虽然它们在某些方面很像,可是实际上倒是不一样的东西,单例模式的目的是限制建立多个对象,避免冲突,好比使用数据库链接池。而享元模式享元模式的目的是共享,避免屡次建立耗费资源,好比使用String类。
简介
代理模式于结构型模式,主要是经过一个类表明另外一个类的功能。一般,咱们建立具备现有对象的对象,以便向外界提供功能接口。
代理模式,如其名,也就是代理做用。 咱们生活中也有很多示例,好比典型的代购,土豪专用的支票,Windows 里面的快捷方式,以及spring中的aop 等等。
代理模式主要由这三个角色组成,抽象角色、代理角色和真实角色。
代理模式又分为静态代理、动态代理。
这里咱们依旧用一个简单的示例来进行说明。
张三和李四是室友,某天,张三在寝室内玩游戏正带劲,感受肚子饿了,本想下楼去吃饭的,可是想起李四可能快要回来,因而打电话给李四,让李四帮本身带份盒饭。这里的李四就扮演着代理者的做用。
首先咱们用静态代理
来实现该功能。
这里实现相对而言较为简单,依旧是定义一个接口,而后定义一个真实的角色,实现该接口的功能,继而定义一个代理者,也实现该接口,可是添加该真实角色的对象进行相应的业务逻辑处理。
那么该静态代理
代码实现以下:
interface Shopping { void buyFood(); } class ExecutePerson implements Shopping { private String name; public ExecutePerson(String name) { this.name = name; } @Override public void buyFood() { System.out.println(name + " 买东西"); } } class ProxyPerson implements Shopping { private ExecutePerson ep; public ProxyPerson(ExecutePerson ep) { this.ep = ep; } @Override public void buyFood() { ep.buyFood(); } } public class ProxyTest { public static void main(String[] args) { String name = "李四"; Shopping shopping = new ProxyPerson(new ExecutePerson(name)); shopping.buyFood(); } }
输入结果:
李四 买东西
在使用静态代理实现该功能以后,咱们发现实现起来很简单,经过一个代理类就能够在不影响目标对象的前提进行扩展使用。可是咱们也发现一个问题,若是咱们不肯定须要代理某个真实类的时候会比较麻烦,并且在类过多的时候,目标对象与代理对象都要维护,会使系统复杂度提高,维护起来也更加麻烦。
不过这时咱们就可使用动态代理
来进行解决。
所谓动态代理
能够没必要强行指定某个真实的角色,只须要在运行时决定就能够了。这里咱们可使用JDK中java.lang.reflect
来进行开发。
JDK对动态代理提供了如下支持:
那么废话不在多说,开始进行代码改造,以前的接口和真实者不须要更改,咱们只须要更改代理者就能够了。
更改以后的代码以下:
class ProxyPerson2 implements InvocationHandler { private Shopping shopping; private final String methodName = "buyFood"; public ProxyPerson2(Shopping shopping) { this.shopping = shopping; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; if (methodName.equals(method.getName())) { result = method.invoke(shopping, args); } return result; } }
测试代码,注意这里调用和以前不一样!
这里经过Proxy类中的newProxyInstance方法会动态生成一个代理类,而后进行调用。其中这三个参数的说明以下:
public class ProxyTest { public static void main(String[] args) { Shopping shopping2 = (Shopping)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Shopping.class}, new ProxyPerson2(new ExecutePerson(name))); shopping2.buyFood(); } }
代理模式优势:
一、职责清晰。 二、高扩展性。 三、智能化。
代理模式缺点:
一、因为在客户端和真实主题之间增长了代理对象,所以有些类型的代理模式可能会形成请求的处理速度变慢。
二、实现代理模式须要额外的工做,有些代理模式的实现很是复杂。
注意事项:
和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
和装饰器模式的区别:装饰器模式为了加强功能,而代理模式是为了加以控制。
代理模式参考:
http://www.runoob.com/design-pattern/proxy-pattern.html
https://baike.baidu.com/item/%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F/8374046
https://blog.csdn.net/zjf280441589/article/details/50411737
分享一首很带感的电音!
java-study是本人在学习Java过程当中记录的一些代码,也包括以前博文中使用的代码。若是感受不错,但愿顺手给个start,固然若是有不足,也但愿提出。
github地址: https://github.com/xuwujing/java-study
原创不易,若是感受不错,但愿给个推荐!您的支持是我写做的最大动力! 版权声明: 做者:虚无境 博客园出处:http://www.cnblogs.com/xuwujing CSDN出处:http://blog.csdn.net/qazwsxpcm 我的博客出处:http://www.panchengming.com