[19/04/25-星期四] GOF23_结构型模式(适配器模式、代理模式)
一、引言
结构模式:核心作用就是从程序的结构上实现松耦合,从而扩大整体的类结构,用来解决更大的问题。
二、适配器模式(adapter)
生活中假设笔记本是标准的USB接口但是外置键盘是圆形接口,这时候就需要一个适配器,如下图所示。一端连接笔记本,一端连接键盘。
用途:一个如下的适配器价格低于一个新的键盘价格,键盘可以打字,现在需要打字但是买不起键盘但可以买得起适配器,这是适配器就有用途了。还比如新型的带USB的插座
也是同样的道理,也是适配器。
概念:将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原来由于接口不兼容而不能在一起工作的那些类可以在一起工作。
角色: 目标接口:客户所希望的接口。目标可以是具体的也可以是抽象的的类,也可以是接口。(如下图中电脑所需要的USB接口)
需要适配的类:需要适配的类或适配者类。(如下图中的 "键盘" 类)
适配器类:通过包装一个需要适配的对象,把原来的接口转换成目标接口。(如下图中的适配器产品)
使用场景:旧系统的升级和改造
Java.io.InputStreamReader(InputStream)
Java.io.OutputStreamReader(OutputStream)
【适配器】
- /**
- * 相当于USB接口
- */
- package cn.sxt.adapter;
- public interface Target {
- void handleRequst();
- }
- /***
- * 适配器本身(一个转接器),既继承被适配类又实现Target接口(相当于USB接口),中间是2边都要熟悉,功能都得具备
- * 类适配器的模式 (因为有继承,extends Adaptee)
- */
- package cn.sxt.adapter;
- public class Adapter extends Adaptee implements Target{
- //重写接口USB的handleRequst方法
- public void handleRequst() {
- super.request();//super指的是Adaptee类对象 request也是它的方法
- }
- }
【被适配对象】
- /***
- * 被适配的类(就是圆形接口(ps/2接口)键盘)
- */
- package cn.sxt.adapter;
- public class Adaptee {
- public void request() {
- System.out.println("可以完成客户需要打字的功能");
- }
- }
- /***
- * 使用对象适配器模式,使用了组合的模式,跟被适配对象整合
- */
- package cn.sxt.adapter;
- public class Adapter2 implements Target{
- private Adaptee adaptee;
- public void handleRequst() {
- adaptee.request();
- }
- public Adapter2(Adaptee adaptee) {
- super();
- this.adaptee = adaptee;
- }
- }
【客户端】
- /***
- * 客户类:相当于笔记本电脑,只有USB接口
- */
- package cn.sxt.adapter;
- public class Client {
- public void test01(Target t) {
- t.handleRequst();
- }
- public static void main(String[] args) {
- Client client=new Client();//一个只有USB接口的笔记本
- Adaptee adpatee=new Adaptee();//一个只有ps/2接口的键盘
- Target target=new Adapter();//Target 一个USB接口
- client.test01(target);
- Target target2=new Adapter2(adpatee);
- client.test01(target2);//结果一样
- }
- }
【类图】
三、代理模式(Proxy Pattern)
核心作用:通过代理,控制对对象的访问 ,可以详细控制访问某个或某类对象的方法,在调用方法前做前置处理(如面谈、签合同),
调用这个方法后做后置处理(如收尾款),即AOP的微观实现。
【AOP扩展】
AOP:Aspect Oriented Programming 面向切面编程。核心机制就是代理模式
一个代理可以代理多个明星的业务(面谈、签合同、收尾款)。核心的业务如唱歌还是要明星自己完成。如果代理的明星多的话,那么代理占据很重要的位置。
每次演唱会都有相同的流程可以将一些相同的流程交给代理去做(如面谈、签合同、收尾款)
AOP:流程好多一样,可以把一样的流程handler中的invoke方法中去处理。它的开源框架是:AspectJ
【代理模式详解】
应用场景:
安全代理:屏蔽对真实角色的访问
远程代理:通过代理类处理远程方法的调用(RMI)
延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象(如:一个文档查看软件,文档中有可能一个图片很大,在打开文件时不可能将所有图片都显示出来
可以使用代理,在需要查看图片时,用代理去打开大的图片。新浪微博9宫格,先看到时缩略图,需要看某个图片可以放大看)
开发框架中应用:
Struts2 中拦截器的实现;数据库连接池的关闭处理;Hibernate中延时加载的实现;mybatis中拦截器插件的实现;AspectJ的实现;
Spring中AOP的实现(日志拦截、声明式事务处理);web service ;RMI远程方法的调用。
分类:
静态代理 (静态定义代理类):代理类由我们自己定义
动态代理(动态生成代理类): 代理类由程序(Java工具表)生成。包括:JDK自带的动态代理、javaassist字节码操作库实现、CGLIB(Code Generation Library)、
ASM(底层使用命令,可维护性差)
1、静态代理
【接口】
- /***
- * 定义一个"明星"接口
- */
- package cn.sxt.staticProxy;
- public interface Star {
- void confer(); //面谈
- void signContract();//签合同
- void bookTicket();//订飞机票
- void sing();//唱歌
- void collectMoney();//收钱
- }
【真实角色】
- /***
- * 真实角色:明星本身
- */
- package cn.sxt.staticProxy;
- public class RealStar implements Star{
- @Override
- public void confer() {
- System.out.println("真实角色(周杰伦本人):面谈");
- }
- @Override
- public void signContract() {
- System.out.println("真实角色(周杰伦本人):签合同");
- }
- @Override
- public void bookTicket() {
- System.out.println("真实角色(周杰伦本人):订飞机票");
- }
- @Override
- public void sing() {
- System.out.println("真实角色(周杰伦本人):唱歌");
- }
- public void collectMoney() {
- System.out.println("真实角色(周杰伦本人):收尾款");
- }
- }
【代理角色】
- /**代理角色:经纪人
- *
- */
- package cn.sxt.staticProxy;
- public class ProxyStar implements Star {
- private Star realStar;
- public ProxyStar(Star realStar) {
- this.realStar=realStar;
- }
- @Override
- public void confer() {
- System.out.println("代理角色(经纪人):面谈");
- }
- @Override
- public void signContract() {
- System.out.println("代理角色(经纪人):签合同");
- }
- @Override
- public void bookTicket() {
- System.out.println("代理角色(经纪人):订飞机票");
- }
- //代理角色什么都能做但是就是不能唱歌,需要调用真实角色去唱歌
- public void sing() {
- realStar.sing();
- }
- public void collectMoney() {
- System.out.println("代理角色(经纪人):收尾款");
- }
- }
【客户】
- /***
- * 客户类
- */
- package cn.sxt.staticProxy;
- public class Client {
- public static void main(String[] args) {
- Star realStar=new RealStar();
- Star proxyStar=new ProxyStar(realStar);//代理类需要传进去一个真实的角色(代理对象)
- proxyStar.confer();
- proxyStar.signContract();
- proxyStar.bookTicket();
- proxyStar.sing();//代理角色(经纪人)需要调用真实角色(周杰伦)去完成唱歌的功能。客户可以只跟经纪人打交道
- proxyStar.collectMoney();
- }
- }
【类图】
2、动态代理
(1) JDK自带动态处理
java.lang.reflect.Proxy 作用:生成代理类和对象
Java.lang.reflect.Invocationhandler(处理器接口) 可以通过invoke方法实现对真实角色的代理访问,每次通过Proxy生成代理类对象时都要指定对应的处理器接口。
【接口】
- /***
- * 定义一个"明星"接口
- */
- package cn.sxt.dynamicProxy;
- public interface Star {
- void confer(); //面谈
- void signContract();//签合同
- void bookTicket();//订飞机票
- void sing();//唱歌
- void collectMoney();//收钱
- }
【真实角色】
- /***
- * 真实角色:明星本身
- */
- package cn.sxt.dynamicProxy;
- public class RealStar implements Star{
- @Override
- public void confer() {
- System.out.println("真实角色(周杰伦本人):面谈");
- }
- @Override
- public void signContract() {
- System.out.println("真实角色(周杰伦本人):签合同");
- }
- @Override
- public void bookTicket() {
- System.out.println("真实角色(周杰伦本人):订飞机票");
- }
- @Override
- public void sing() {
- System.out.println("真实角色(周杰伦本人):唱歌");
- }
- public void collectMoney() {
- System.out.println("真实角色(周杰伦本人):收尾款");
- }
- }
【处理核心】
- /**
- *
- */
- package cn.sxt.dynamicProxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- public class StarHandler implements InvocationHandler {
- Star realsStar;
- public StarHandler(Star realsStar) {
- this.realsStar = realsStar;
- }
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- System.out.println("####");//代理类不管调用什么方法都会到这里集中报道
- System.out.println("真正方法(唱歌)执行前:面谈、签合同、预付款、订机票");
- if ( method.getName().equals("sing") ) {//如果是唱歌方法激活真实角色的唱歌方法
- method.invoke(realsStar, args);//激活传入对象的 args(形参)方法
- }
- System.out.println("真正方法(唱歌)执行后:付尾款");
- return null;
- }
- }
【客户端】
- /**客户类
- *
- */
- package cn.sxt.dynamicProxy;
- import java.lang.reflect.Proxy;
- public class Client {
- public static void main(String[] args) {
- Star realStar=new RealStar();
- StarHandler handler=new StarHandler(realStar);
- Star proxyStar=(Star)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
- new Class[] {Star.class}, handler);//返回一个代理对象 proxyStar
- proxyStar.confer();
- proxyStar.sing();
- proxyStar.collectMoney();
- }
- }
【类图】
[19/04/25-星期四] GOF23_结构型模式(适配器模式、代理模式)的更多相关文章
- [19/04/28-星期日] GOF23_结构型模式(享元模式)
一.享元模式(FlyWeight,轻量级) [共享类与非共享类] /*** *FlyweightFactory享元工厂类: 创建并管理享元对象,享元池一般设计成键值对 */ package cn.sx ...
- 结构型设计模式之代理模式(Proxy)
结构 意图 为其他对象提供一种代理以控制对这个对象的访问. 适用性 在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用P r o x y 模式.下面是一 些可以使用P r o x y 模式常见 ...
- 结构型模式(七) 代理模式(Proxy)
一.动机(Motivate) 在面向对象系统中,有些对象由于某种原因(比如对象创建的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等),直接访问会给使用者.或者系统结构带来很多麻烦.如何在不 ...
- Java进阶篇设计模式之七 ----- 享元模式和代理模式
前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...
- Java设计模式之七 ----- 享元模式和代理模式
前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...
- 10.JAVA-接口、工厂模式、代理模式、详解
1.接口定义 接口属于一个特殊的类,这个类里面只能有抽象方法和全局常量 (该概念在JDK1.8之后被打破,在1.8后接口中还可以定义普通方法和静态方法,在后续章节会详讲) 1.1 接口具有以下几个原 ...
- axios 两种异步模式,代理模式 和 异步模式
axios 两种异步模式,代理模式 和 异步模式
- [转载]Java中继承、装饰者模式和代理模式的区别
[转载]Java中继承.装饰者模式和代理模式的区别 这是我在学Java Web时穿插学习Java设计模式的笔记 我就不转载原文了,直接指路好了: 装饰者模式和继承的区别: https://blog.c ...
- 初探Java设计模式2:结构型模式(代理模式,适配器模式等)
行为型模式 行为型模式关注的是各个类之间的相互作用,将职责划分清楚,使得我们的代码更加地清晰. 策略模式 策略模式太常用了,所以把它放到最前面进行介绍.它比较简单,我就不废话,直接用代码说事吧. 下面 ...
随机推荐
- ROS:消息发布器和订阅器(c++)
学习资料主要源自http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29 $ roscd beginner_t ...
- UVA 455(最小周期)
最小周期可以用%枚举 #include <iostream> #include <string> #include <cstring> #include <c ...
- spss C# 二次开发 学习笔记(三)——Spss .Net 开发
Spss .Net 二次开发的学习过程暂停了一段时间,今天开始重启. 之前脑残的不得了,本想从网上下载一个Spss的安装包,然后安装学习.于是百度搜索Spss,在百度搜索框的列表中看到Spss17.S ...
- SQL修改表结构
--(1)向数据库Student表中添加Name字段 use MR_NXT alter table student add Name char(20) --(2)将Student表中Name的字段的数 ...
- python_Django 实现登入功能form表单的参数接收处理
1.创建Django工程. 参考https://www.cnblogs.com/CK85/p/10159159.html中步骤. 2.在urls.py文件中添加url分发路径 "" ...
- h5 简单拖放
最新的HTML5标准为所有的html元素规定了一个draggable属性,它表明了元素是否可以拖动,默认情况下,图像,链接,选中的文字是可以拖动的,因为他们的draggable属性被自动设置为true ...
- 地图的平移、缩放的实现(android版)
一.平移地图 移动地图的原理是利用手指在屏幕上拖动的距离,转换为在地图上距离,把地图坐标加上偏移的距离实现地图移动. 由于地图是绘制到Bitmap上的,所以地图移动和缩放的过程只要改变Bitmap的矩 ...
- ODP.Net Tips
Overview Oracle Data Provider for .NET是Oracle 提供的.Net版本的数据库连接组件.下载路径. 使用的核心DLL是Oracle.DataAccess.dll ...
- Bootstrap 在线引用
Bootstrap 3.3.0 js 文件 <script src="http://cdn.bootcss.com/bootstrap/3.3.0/js/bootstrap.min.j ...
- Ubuntu 16.04 Apache2 更改访问html根路径方案(可解决403)
(1)确定html文件在服务器主机上的部署路径.例:/home/rl/vc/ (2)修改 vim sites-enabled/000-default.conf 中 DirectoryRoot 为 : ...