一、引言

结构模式:核心作用就是从程序的结构上实现松耦合,从而扩大整体的类结构,用来解决更大的问题。

二、适配器模式(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_结构型模式(适配器模式、代理模式)的更多相关文章

  1. [19/04/28-星期日] GOF23_结构型模式(享元模式)

    一.享元模式(FlyWeight,轻量级) [共享类与非共享类] /*** *FlyweightFactory享元工厂类: 创建并管理享元对象,享元池一般设计成键值对 */ package cn.sx ...

  2. 结构型设计模式之代理模式(Proxy)

    结构 意图 为其他对象提供一种代理以控制对这个对象的访问. 适用性 在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用P r o x y 模式.下面是一 些可以使用P r o x y 模式常见 ...

  3. 结构型模式(七) 代理模式(Proxy)

    一.动机(Motivate) 在面向对象系统中,有些对象由于某种原因(比如对象创建的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等),直接访问会给使用者.或者系统结构带来很多麻烦.如何在不 ...

  4. Java进阶篇设计模式之七 ----- 享元模式和代理模式

    前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...

  5. Java设计模式之七 ----- 享元模式和代理模式

    前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...

  6. 10.JAVA-接口、工厂模式、代理模式、详解

    1.接口定义 接口属于一个特殊的类,这个类里面只能有抽象方法和全局常量  (该概念在JDK1.8之后被打破,在1.8后接口中还可以定义普通方法和静态方法,在后续章节会详讲) 1.1 接口具有以下几个原 ...

  7. axios 两种异步模式,代理模式 和 异步模式

    axios 两种异步模式,代理模式 和 异步模式

  8. [转载]Java中继承、装饰者模式和代理模式的区别

    [转载]Java中继承.装饰者模式和代理模式的区别 这是我在学Java Web时穿插学习Java设计模式的笔记 我就不转载原文了,直接指路好了: 装饰者模式和继承的区别: https://blog.c ...

  9. 初探Java设计模式2:结构型模式(代理模式,适配器模式等)

    行为型模式 行为型模式关注的是各个类之间的相互作用,将职责划分清楚,使得我们的代码更加地清晰. 策略模式 策略模式太常用了,所以把它放到最前面进行介绍.它比较简单,我就不废话,直接用代码说事吧. 下面 ...

随机推荐

  1. Google Voice号码使用说明及用途

    Google Voice号码使用说明及用途 号码 已不能网页注册获取,直接向TB购买,搜Google Voice就行了.很便宜的. 一. Google Voice介绍 Google Voice首先是一 ...

  2. 第一章Bootstrap简介

    一.Bootstrap简介 Bootstrap是基于 HTML.CSS.JAVASCRIPT 的前端框架,它简洁灵活,使得 Web 开发更加快捷.它由Twitter的设计师Mark Otto和Jaco ...

  3. bootstrap fileinput +springmvc图片上传-krajee

    引入的文件 <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/4.4.9/css/filei ...

  4. 浏览器根对象window之值为字符串的属性

    1. string属性 1.1 origin window.origin使用返回的是当前网页的网址.打开百度首页,并在控制台中输入 window.origin 控制台中会输出"https:/ ...

  5. Android 一种非常好用的Android屏幕适配

    前言 网上关于屏幕适配的文章已经铺天盖地了,为什么我还要讲?因为网上现在基本都是使用px适配,即每种屏幕分辨率的设备需要定义一套dimens.xml文件.再加上有些手机还有虚拟按键(例如华为),这样就 ...

  6. 获取所有后缀DDE打开命令

    概述: 由于需要使用DDE方式打开文件,所以把支持DDE方式打开文件的参数都导出来到文件,方便查找. 并且提供运行DDE命令的工具,可以用于测试DDE功能. 1.运行脚步GetDDE.vbs可以获取系 ...

  7. 微信小程序开发7-JavaScript脚本

    1.小程序的主要开发语言是 JavaScript ,开发者使用 JavaScript 来开发业务逻辑以及调用小程序的 API 来完成业务需求. 2.ECMAScript 在大部分开发者看来,ECMAS ...

  8. 简单的3proxy配置

    timeouts 1 5 30 60 180 1800 15 60log "D:\Program Files\3proxy-0.6.1-x64\cfg\3proxy.log" Dl ...

  9. Mysql rpm安装

    总结下mysql rpm安装的方式,与一些错误 环境[root@host2 ~]# uname -aLinux host2 2.6.32-504.3.3.el6.x86_64 #1 SMP Wed D ...

  10. CSS transitions深入理解

    到底css transition是什么,我们来看w3c的解释: CSS Transitions allow property changes in CSS values to occur smooth ...