二十三种设计模式详解
1 动态代理
代理是什么?
代理其实就是代为处理的意思,个人理解就是产生一个处理类对需要代理的对象进行处理,并且返回该代理对象
静态代理
首先实现一个Moveable接口,表示代理与被代理的对象都属于同一个类别
public interface Moveable {void move();void stop();
}
接下来实现一个被代理对象坦克类,有着坦克开始与结束的方法
public class Tank implements Moveable{@Overridepublic void move() {System.out.println("Tank moving 。。");try {Thread.sleep(new Random().nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic void stop() {System.out.println("Tank stop");}
}
接下来如果想要知道Tank的move方法允许了多久的话,最直接的就是使用继承方法,但是如果使用继承的话,想要再知道运行的日志的话就需要再继承扩展一个类,因此使用聚合来解耦合。
实现时间代理
public class TankTimeProxy implements Moveable{Moveable t;public TankTimeProxy(Moveable t) {super();this.t = t;}@Overridepublic void move() {Long start = System.currentTimeMillis();t.move();long end = System.currentTimeMillis();System.out.println(end-start);}@Overridepublic void stop() {Long start = System.currentTimeMillis();t.stop();long end = System.currentTimeMillis();System.out.println(end-start);}
}
实现日志代理
public class TankLogProxy implements Moveable{Moveable t;public TankLogProxy(Moveable t) {super();this.t = t;}@Overridepublic void move() {System.out.println("Tank start");t.move(); //这里调用的其实是Tank的方法long end = System.currentTimeMillis();System.out.println("Tank end");}@Overridepublic void stop() {}
}
调用地方的代码如下
public static void main(String[] args) throws NoSuchMethodException, IOException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {Tank t =new Tank();TankTimeProxy ttp =new TankTimeProxy(t);TankLogProxy tlp = new TankLogProxy(ttp); //在时间代理上再加上日志代理
// Moveable m = tlp;Moveable m = tlp;m.move();
}
打印数据的数据如下
Tank start
Tank moving 。。
861
Tank end
动态代理
(这里借用网上的例子,代码已经测过无误)
在完成了静态代理之后,我们需要考虑另外的问题,如果在我们需要计算的是除了move之外的其他方法的运行时间,那么岂不是又要生成一个代理类了?多个方法的话就是多个代理类,会导致类无限制扩展。因此就用到了动态代理
使用动态代理需要用到反射,反射是用于获取已创建实例的方法或者属性,并对其进行调用或者赋值。在这里我们可以动态一个代理对象,并且动态编译。然后,再通过反射创建对象并加载到内存中,就实现了对任意对象进行代理
第一步:定义自己的一个代理的逻辑处理接口,用来实现处理自定义逻辑
public interface InvocationHandler {void invoke(Object o, Method m) throws InvocationTargetException, IllegalAccessException;
}
第二步:定义一个运行时间处理器,用来处理代理对象,
public class TimeHandler implements InvocationHandler {//被代理的对象private Object target;public TimeHandler(Object target) {this.target = target;}public Object getTarget() {return target;}public void setTarget(Object target) {this.target = target;}// o 是代理对象@Overridepublic void invoke(Object o, Method m) throws InvocationTargetException, IllegalAccessException {long start = System.currentTimeMillis();System.out.println("starttiem: "+ start);m.invoke(target); //调用被代理对象原来的方法long end = System.currentTimeMillis();System.out.println("time: " + (end -start));}
}
第三步:编写动态代理的代码:
public class Proxy {/*** 动态代理* 产生新的代理类* infce 产生对应接口的代理 该接口对应的处理方法* @return*/public static Object newProxyInstance(Class infce, InvocationHandler h) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {String methodStr = "";Method[] methods = infce.getMethods();String rt = "\r\n";for(Method m : methods) { //动态代码 编译后动态生成一个对象,该对象包含着InvocationHandler,methodStr += "@Override" + rt +"public void " + m.getName() + "() {" + rt +" try {" + rt +" Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +" h.invoke(this, md);" + rt + //传入的是this" }catch(Exception e) {e.printStackTrace();}" + rt +"}";}String src ="package com.bjsxt.proxy;" + rt +"import java.lang.reflect.Method;" + rt +"public class $Proxy1 implements " + infce.getName() + "{" + rt +" public $Proxy1(InvocationHandler h) {" + rt +" this.h = h;" + rt +" }" + rt +" com.bjsxt.proxy.InvocationHandler h;" + rt +methodStr +"}";String fileName ="d:/src/com/bjsxt/proxy/$Proxy1.java";File f = new File(fileName);FileWriter fw = new FileWriter(f);fw.write(src);//将要编译的代码写到文件中去fw.flush();fw.close();//编译TimeProxy源码JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);Iterable units = fileMgr.getJavaFileObjects(fileName);JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);t.call();fileMgr.close();//加载到内存中并创建对象URL[] urls = new URL[] {new URL("file:/" + "d:/src/")};URLClassLoader ul = new URLClassLoader(urls);Class c = ul.loadClass("com.bjsxt.proxy.$Proxy1");System.out.println(c);//传过来那个处理器就按照那个处理器去实现Constructor ctr = c.getConstructor(InvocationHandler.class);Object m = ctr.newInstance(h);//m.move();return m;}
}
第四步:调用:
public static void main(String[] args) throws Exception {Tank t = new Tank();InvocationHandler h = new TimeHandler(t);Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h);m.move();}
在这里Proxy.newProxyInstance(Moveable.class, h)生成的Proxy1代理类为:
class Prox1 implements Moveable {private InvocationHandler handler;public TimeProxy(InvocationHandler handler) {this.handler = handler;}@Overridepublic void move() {try {Method method = com.youngfeng.proxy.Flyable.class.getMethod("move");this.handler.invoke(this, method, null);} catch(Exception e) {e.printStackTrace();}}
}
方法调用链:Proxy1 . move() -> TimeHandler.invoke(Object o, Method m) -> Tank.move();
主要逻辑
- Proxy->newProxyInstance(infs, handler) 用于生成代理对象
- InvocationHandler:这个接口主要用于自定义代理逻辑处理
- 为了完成对被代理对象的方法拦截,我们需要在InvocationHandler对象中传入被代理对象实例。
因此对其他对象进行代理就不再需要修改newProxyInstance方法中的代码
2 策略模式
策略模式主要用于不同的类根据不同的方法去解决,比如一只猫的属性有体重跟身高,实现按身高进行排序与按体重进行排序,即可使用策略模式
- Comparable表明实现该接口的类必须实现compare方法,
- Comparator则是比较器的具体实现
第一步:定义一个实现了Comparable的Cat类
public class Cat implements Comparable{int Height;int weight;Comparator comparator;public int getHeight() {return Height;}public void setHeight(int height) {Height = height;}public int getWeight() {return weight;}public void setWeight(int weight) {this.weight = weight;}public Comparator getComparator() {return comparator;}public void setComparator(Comparator comparator) {this.comparator = comparator;}@Overridepublic int compareTo(Object o) {return comparator.compare(this, o);}
}
在这个类里面实现了一个继承器,传入自己实现的Comparator可以实现对身高和体重进行比较。
第二步:实现一个接口类使它的实现类确定实现了compareTo方法
public interface Comparable {int compareTo(Object o);
}
第三步:实现一个比较器的接口:
public interface Comparator {int compare(Object o1, Object o2);
}
第四步:继承Comparator接口实现身高比较器
public class CatHeightComparator implements Comparator{@Overridepublic int compare(Object o1, Object o2) {Cat c1 = (Cat)o1;Cat c2 = (Cat)o2;if (c1.getHeight() > c2.getHeight()) return 1;else if (c1.getHeight() > c2.getHeight()) return -1;return 0;}
}
策略模式其实就是需要变化的类其中聚合一个策略,根据需要传入不同的实现类实现不同的需要
3 状态模式
状态模式使用对象的形式来记录某种状态。使用状态模式可以省去多个if-else或者是switch的判断。可以直接使用对象方法的形式来处理逻辑。
例如在这里实现两个类Boy和MM类,其中MM中包含了抽象类State。代表了MM此时的心情
public class Boy {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}}
public class MM {private MMState state = new MMHappyState();private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void smile(){state.smile();}public void cry(){state.cry();}public void say(){state.say();}
}
抽象类MyState
public abstract class MMState {public abstract void smile();public abstract void cry();public abstract void say();
}
代表MM好心情的MMHappyState
public class MMHappyState extends MMState{@Overridepublic void smile() {}@Overridepublic void cry() {}@Overridepublic void say() {}
}
因此当MM状态改变时,比如从开心的哭变成悲伤的哭只需要改变State即可,不需要修改其他代码。
4 工厂模式
抽象工厂
当需要新的工厂时直接继承VehicleFactory就可以
第一步:Moveable接口
public interface Moveable {void run();
}
所有的交通工具都实现了该接口
第二步:定义了汽车和飞机类
public class Plane implements Moveable{@Overridepublic void run() {System.out.println("plane");}
}public class Car implements Moveable{private static Car c = new Car();public void run(){System.out.println("run");}//静态工厂方法 用来产生car产品public static Car getInstance(){return c;}
}
第三步:实现一个工厂类,负责实现创建所有实例的内部逻辑。
public abstract class VehicleFactory {abstract Moveable create();
}
第四步: 实现工厂接口
public class PlaneFactory extends VehicleFactory{@OverrideMoveable create() {return new Plane();}
}public class CarFactory extends VehicleFactory{@OverrideMoveable create() {return new Car();}
}
在调用时需要那个类的工厂直接new它的工厂就行
public static void main(String[] args) {VehicleFactory factory = new PlaneFactory();Moveable m = factory.create();m.run();}
5 责任链模式
使多个对象都有处理请求的机会,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象串成一条链,并沿着这条链一直传递该请求,直到有对象处理它为止。
目标
用Filter模拟处理Request、Response
思路技巧
(1)Filter的doFilter方法改为doFilter(Request,Resopnse,FilterChain),有FilterChain引用,为利用FilterChain调用下一个Filter做准备
(2)FilterChain继承Filter,这样,FilterChain既是FilterChain又是Filter,那么FilterChain就可以调用Filter的方法doFilter(Request,Resopnse,FilterChain)
(3)FilterChain的doFilter(Request,Resopnse,FilterChain)中,有index标记了执行到第几个Filter,当所有Filter执行完后request处理后,就会return,以倒序继续执行response处理
代码如下:
Filter.java
public interface Filter {void doFilter (Request request, Response response,FilterChain filterChain);
}
HTMLFilter.java :替换HTML代码
public class HTMLFilter implements Filter {@Overridepublic void doFilter(Request request, Response response,FilterChain filterChain) {request.setRequestStr(request.getRequestStr().replace('<', '[').replace(">", "]")+"---HTMLFilter()");filterChain.doFilter(request, response, filterChain);response.setResponseStr(response.getResponseStr()+"---HTMLFilter()");}
}
3.SensitiveFilter.java 替换敏感词汇
public class SensitiveFilter implements Filter {@Overridepublic void doFilter(Request request, Response response,FilterChain filterChain) {request.setRequestStr(request.getRequestStr().replace("敏感", "幸福")+"---SensitiveFilter()");filterChain.doFilter(request, response, filterChain);response.setResponseStr(response.getResponseStr()+"---SensitiveFilter()");}}
4.FilterChian.java 过滤器链
public class FilterChain implements Filter {private List<Filter> filters = new ArrayList<Filter>();int index = 0; //标记执行到第几个filter//把函数的返回值设为FilterChain,返回this,就能方便链式编写代码public FilterChain addFilter(Filter filter) {filters.add(filter);return this;}public void doFilter(Request request, Response response, FilterChain fc) {if(index == filters.size()) return ;Filter f = filters.get(index);index++;f.doFilter(request, response, fc);}
}
5.Request.java 和 Response.java
public class Request {private String requestStr;public String getRequestStr() {return requestStr;}public void setRequestStr(String requestStr) {this.requestStr = requestStr;}}public class Response {private String responseStr;public String getResponseStr() {return responseStr;}public void setResponseStr(String responseStr) {this.responseStr = responseStr;}}
6Test.java
public class Test {@org.junit.Testpublic void testFilter(){String msg = "<html>敏感字眼</html>"; Request request = new Request();request.setRequestStr(msg);Response response = new Response();response.setResponseStr("response------------");FilterChain fc = new FilterChain();fc.addFilter(new HTMLFilter()).addFilter(new SensitiveFilter());fc.doFilter(request, response, fc);System.out.println(request.getRequestStr());System.out.println(response.getResponseStr());}}
6 命令模式
命令也是类,将命令作为一个类来保存,当要使用的时候可以直接拿来使用
1.Client.java
public class Client {public void request(Server server){server.addCommand(new TextCommand());server.addCommand(new ImageCommand());server.doSomething();}}
2.Server.java
public class Server {private List<Command> commands = new ArrayList<Command>();public void doSomething() {for(Command c : commands){c.execute();}}public void addCommand(Command command) {commands.add(command);}}
3.Command.java
public abstract class Command {public abstract void execute();public abstract void unDo();}
4.TextCommand.java
public class TextCommand extends Command {@Overridepublic void execute() {System.out.println("TextCommand...........");}@Overridepublic void unDo() {// 涉及到操作的历史记录}}
5.ImageCommand.java
public class ImageCommand extends Command {@Overridepublic void execute() {System.out.println("ImageCommand...........");}@Overridepublic void unDo() {// 涉及到操作的历史记录}}
6.Test.java
public class Test {@org.junit.Testpublic void test(){Client c = new Client();c.request(new Server());}}
7 桥接模式
设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有如下两种设计方案:
• 第一种设计方案是为每一种形状都提供一套各种颜色的版本。
• 第二种设计方案是根据实际需要对形状和颜色进行组合。
模式定义
桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式
应用情况:(1)两个维度扩展(2)排列组合
1.Gift.java 礼物
public class Gift {GiftImpl impl;
}
2.GiftImpl.java 继承该类是具体物品
public class GiftImpl {}
3.WarmGift.java
public class WarmGift extends Gift {public WarmGift(GiftImpl giftImpl) {//调用父类的giftImplthis.giftImpl = giftImpl;}@Overridepublic String toString() {return this.getClass().getName()+"-----"+giftImpl.getClass().getName();}
}
4.WildGift.java
public class WildGift extends Gift {public WildGift(GiftImpl giftImpl) {//调用父类的giftImplthis.giftImpl = giftImpl;}@Overridepublic String toString() {return this.getClass().getName()+"-----"+giftImpl.getClass().getName();}
}
5.Flower.java
public class Folwer extends GiftImpl{}
6.Ring.java
public class Ring extends GiftImpl{}
7.MM.java
public class MM {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}}
8.Boy.java
pursue(MM mm)是送给女孩子礼物的方法 想要送不同的礼物修改gift = new WildGift(new Flower())即可
public class Boy {private String name;public void pursue(MM mm){Gift gift = new WildGift(new Flower());give(gift, mm);System.out.println(gift);}public void give(Gift gift, MM mm) {}
}
9.Test.java
public class Test {@org.junit.Testpublic void test() {Boy b = new Boy();b.pursue(new MM());}}
二十三种设计模式详解相关推荐
- 23 种设计模式详解
转自原文 23 种设计模式详解(全23种) 设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种: 工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种: 适配 ...
- 二十三种设计模式-六大原则
二十三种设计模式 一.创建型: 单例模式.工厂模式.抽象工厂模式.原型模式.建造者模式: 二.结构型: 代理模式,装饰器模式.适配器模式.外观模式.组合模式.享元模式.桥梁模式: 三.行为型: 策略模 ...
- Java二十三种设计模式 之代理(proxy)
Java二十三种设计模式 之代理(proxy) 今天我们学习一下静态代理和动态代理 我们来看代码(写一个坦克运行了多少时间): 第一种方法: public calss Tank implements ...
- 二十三种设计模式(第十二种)-----代理模式(Proxy)
二十三种设计模式(第十二种)-----代理模式(Proxy) 尚硅谷视频连接https://www.bilibili.com/video/BV1G4411c7N4?from=search&se ...
- 二十三种设计模式之原型模式
今天继续探讨GOF二十三种设计模式的原型模式,原型模式也是属于创建型模式的一种 原型模式通俗的讲就是对象复制的过程,即通过一个原型对象,我可以得到一个该对象的克隆. 下面来看下原型模式的第一种写法-- ...
- 23种设计模式详解(代码讲解、持续更新)
目录 设计模式分类 设计模式的六大原则 创建型模式 1.工厂方法模式(Factory Method) 2.建造者模式(Builder Pattern(常用.常见)) 行为型模式 模板模式(Templa ...
- 深入理解常见的二十三种设计模式
深入理解常见的二十三种设计模式 文章目录 深入理解常见的二十三种设计模式 一.设计模式的分类 1.1 创建型(五种) 1.2 结构型(七种) 1.3 行为型(十一种) 二.创建型 2.1 单例模式 2 ...
- 第二部分:二十三种设计模式解读——什么是工厂方法模式
二十三种设计模式解读--什么是工厂方法模式 author:陈镇坤27 日期:2022年2月10日 修改日期:2022年6月23日 文章目录 二十三种设计模式解读--什么是工厂方法模式 一.工厂方法模式 ...
- Java实现二十三种设计模式(五)—— 十一种行为型模式 (中)——解释器模式、迭代器模式、中介者模式、备忘录模式
Java实现二十三种设计模式(五)-- 十一种行为型模式 (中)--解释器模式.迭代器模式.中介者模式.备忘录模式 一.解释器模式 我国 IT 界历来有一个汉语编程梦,虽然各方对于汉语编程争论不休,甚 ...
最新文章
- 常考数据结构与算法:合并k个已排序的链表
- Java 消息机制之回调详解
- Python urllib与requests、XML和HTMLParser
- node 16位 转24位_C代码实现16位和32位数据字节序转换
- ASP.NET生成静态页面方法大全(1)
- 下行文格式图片_收藏!公文写作格式大全(附示例图)
- LLVM 4中将加入新的LLVM链接器LLD
- jsp springmvc 视图解析器_SpringMVC 视图解析器
- OMP算法的物理意义表示
- 吐槽一下:武装GoldenDict时,好一个OALD,RAR格式,12万多的文件,晕!!
- python凹多边形分割_在Python中OpenCV多边形的凹凸角点
- 【论文解读】 FPGA实现卷积神经网络CNN(二): Optimizing FPGA-based Accelerator Design for DCNN
- aggr代码 cellranger_CellRanger初探
- Cura工程环境配置教程
- 9.5 隐函数求导法则
- SAP SHDB(BDC)心得
- VBA的参数传递:ByVal 和 ByRef 的区别
- MATLAB 函数大全
- SQL中的WHILE循环使用
- ”全球软件测试实践“问卷调查报告
热门文章
- HTML table 和 div
- 求1+2+…+n变态问题的两个很棒的解法
- 安装Sqlserver2008的问题
- 基于主机Overlay和自研虚拟化网关的VPC在360的落地
- 反思,今天总体感觉事情很简单,但项目比较多,没有掌握住很好的技巧,所以感觉很混乱
- 《Go 语言程序设计》读书笔记 (三) 方法
- Rand7()实现Rand10()
- @JsonFormat与@DateTimeFormat注解的使用
- 解决URI is not registered (Settings | Languages Frameworks | Schemas and DTDs)
- docker-compose搭建kafka集群