马士兵-23设计模式

马士兵-23设计模式

一、模式

1. 单例Singleton

8种写法,2种完美。

1-1. 应用场景

  • 比如各种Manager
  • 比如 各种Factory
  1. //饿汉式 
  2. private static final Mgr01 INSTANCE=new Mgr01();//private main方法客户端 就无法new出多余对象实例 
  3. private Mgr01(){}; 
  4. public static Mgr01 getInstance(){return INSTANCE;} 

2. 策略Strategy

策略就是if分支逻辑的改写。

  • Comparable
  • Comparator

1.8之后接口里面必须有方法实现,为了支持lambda表达式。

策略类图
策略类图

  1. public class DogComparator implements Comparator<Dog>{ 
  2. @Override 
  3. public int compare(Dog o1, Dog o2) { 
  4. return o1.food-o2.food; 
  5. } 
  6. } 
  7. public class Sorter3<T> { 
  8. /*通过泛型实现动态类型比较器的排序方法*/ 
  9. public void sort(T[] a,Comparator<T> comparator) {//不可能每种类型都要写一遍排序,所以要求要排序的类实现comparato方法, 
  10. // 传进来的参数如果是Object接收参数,Object又没实现comparato,所以可以使用Comparable,里面实现了方法, 
  11. // 方法里是compara(Object o),所以object要强所在的类的类型,再去比较 
  12. for (int i = 0; i < a.length; i++) { 
  13. int minPos=i; 
  14. for (int j = i+1; j < a.length; j++) { 
  15. minPos=comparator.compare(a[j],a[minPos])==-1?j:minPos;//第二步:调用比较器 
  16. } 
  17. swap(a,i,minPos); 
  18. } 
  19. } 
  20.  
  21. private void swap(T[] a, int i, int j) { 
  22. T temp=a[i]; 
  23. a[i]=a[j]; 
  24. a[j]=temp; 
  25. } 
  26.  
  27.  
  28. } 
  29.  
  30. public class Main { 
  31. public static void main(String[] args) { 
  32. // int[] a={9,2,3,5,7,1,4}; 
  33. // Cat2[] a={new Cat2(3,3),new Cat2(5,5),new Cat2(1,1)}; 
  34. Dog[] a={new Dog(2),new Dog(3),new Dog(5),new Dog(0)}; 
  35. Sorter3 sorter=new Sorter3(); 
  36. sorter.sort(a,new DogComparator()); 
  37. System.out.println(Arrays.toString(a)); 
  38. } 
  39. } 
  40. //----------------------------------------------函数式 
  41. public class Main { 
  42. public static void main(String[] args) { 
  43. // int[] a={9,2,3,5,7,1,4}; 
  44. // Cat2[] a={new Cat2(3,3),new Cat2(5,5),new Cat2(1,1)}; 
  45. Dog[] a={new Dog(2),new Dog(3),new Dog(5),new Dog(0)}; 
  46. Sorter3<Dog> sorter=new Sorter3(); 
  47. // sorter.sort(a,new DogComparator()); 
  48. sorter.sort(a,(o1,o2)->{return o1.food-o2.food;}); 
  49. System.out.println(Arrays.toString(a)); 
  50. } 
  51. } 
  52.  

3. 第三第四工厂和抽象工厂Factory

3-1. 工厂系列

  • 简单工厂
  • 静态工厂
  • 工厂方法
  • 抽象工厂
  • Spring IOC(控制翻转,动态注入)

3-2. 定义

  • 任何可以产生对象的方法或类,都可以称之为工厂
  • 单例也是一种工厂
  • 不可咬文嚼字,死抠概念2
  • 为什么有了new之后,还要有工厂
    • 灵活控制2生产过程
    • 权限,修饰,日志。。。

3-3. 举例

  • 任意定义交通工具:继承Moveable
  1. public interface Moveable { 
  2. void go(); 
  3. } 
  4. public class Broom implements Moveable{ 
  5. @Override 
  6. public void go() { 
  7. System.out.println("Broom在跑"); 
  8. } 
  9. } 
  10. public class Main 
  11. { 
  12. public static void main(String[] args) { 
  13. Moveable m=new Broom(); 
  14. m.go(); 
  15. } 
  16. } 
  17.  
  18. //----------------------- 
  19. public class Car implements Moveable{ 
  20. @Override 
  21. public void go(){ 
  22. System.out.println("Car 在跑"); 
  23. } 
  24. } 
  25.  
  • 任意定制生产过程:使用Moveable XXFactory.create方法
  1. public class CarFacory { 
  2. public Moveable createCar(){ 
  3. // 日志操作 
  4. System.out.println("car的交通工具扩展工厂"); 
  5. return new Car(); 
  6. } 
  7. } 
  • 任意定制产品一族
  1. /** 
  2. * create-date:2022/6/28 
  3. * author:guojia.ma 
  4. * 工厂下调用实现就不需要在客户端new创建实例了, 
  5. */ 
  6. public class Main { 
  7. public static void main(String[] args) { 
  8. ModernFactory f = new ModernFactory(); 
  9. Vehicle c = f.createVehicle(); 
  10. Weapon w = f.createWeapon(); 
  11. Food b = f.createFood(); 
  12. c.go();w.shoot();b.printName(); 
  13. } 
  14. } 
  15. public abstract class AbstractFactory { 
  16. abstract Food createFood(); 
  17. abstract Vehicle createVehicle(); 
  18. abstract Weapon createWeapon(); 
  19. } 
  20. public class AK47 extends Weapon{ 
  21. @Override 
  22. void shoot() { 
  23. System.out.println("tuutututu"); 
  24. } 
  25. } 
  26. public class Bread extends Food{ 
  27. @Override 
  28. void printName() { 
  29. System.out.println("wdm"); 
  30.  
  31. } 
  32. } 
  33. public class Broom extends Vehicle{ 
  34. @Override 
  35. void go() { 
  36. System.out.println("扫把飞"); 
  37. } 
  38. } 
  39. public class Car extends Vehicle{ 
  40. @Override 
  41. void go() { 
  42. System.out.println("轿车 跑"); 
  43. } 
  44. } 
  45. public abstract class Food { 
  46. abstract void printName(); 
  47. } 
  48. public class MagicFactory extends AbstractFactory{ 
  49. @Override 
  50. Food createFood() { 
  51. return new MushRoom(); 
  52. } 
  53.  
  54. @Override 
  55. Vehicle createVehicle() { 
  56. return new Broom(); 
  57. } 
  58.  
  59. @Override 
  60. Weapon createWeapon() { 
  61. return new MagicStrick(); 
  62. } 
  63. } 
  64. public class MagicStrick extends Weapon{ 
  65. @Override 
  66. void shoot() { 
  67. System.out.println("电击"); 
  68. } 
  69. } 
  70. public class ModernFactory extends AbstractFactory{ 
  71. @Override 
  72. Food createFood() { 
  73. return new Bread(); 
  74. } 
  75.  
  76. @Override 
  77. Vehicle createVehicle() { 
  78. return new Car(); 
  79. } 
  80.  
  81. @Override 
  82. Weapon createWeapon() { 
  83. return new AK47(); 
  84. } 
  85. } 
  86. /** 
  87. * create-date:2022/6/27 
  88. * author:guojia.ma 
  89. * 三类:武器,食品,交通工具 
  90. * 针对现代人:是AK47,Bread,Car(一个族的概念) 
  91. * 针对魔法人: 是MagicBrick,MushRoom,Broom 
  92. */ 
  93. public class MushRoom extends Food{ 
  94. @Override 
  95. void printName() { 
  96. System.out.println("花蘑菇"); 
  97. } 
  98. } 
  99. public abstract class Vehicle { 
  100. abstract void go(); 
  101. } 
  102. public abstract class Weapon { 
  103. abstract void shoot(); 
  104. } 
  105.  

在简单工厂使用了接口Moveable,而在抽象工厂用了抽象类Food;差异其实是语义的区别,比如Move是属性,可能还有其他用接口,后续可以多实现扩展;而Food是具体概念,但是不是具体面包还是什么,但是基本固定用抽象类做继承关系即可。

  • 形容词用接口
  • 名词用抽象类

工厂一个产品族的案例图
工厂一个产品族的案例图

工厂方法,产品好扩展;而产品族的扩展抽象工厂比较方便,但是需要该一堆抽象工厂(族的工厂,产品的工厂)的工厂方法实现。

3-4. 更好的解决方案

  • spring ioc
  • bean工厂

4. 第五第六门面-调停者Mediator(消息中间件)

调停者常用两种场景
调停者常用两种场景

对外叫门面Facade,对内叫调停者Mediator

5. 装饰器Decorator

5-1. 问题

  • 坦克想加一个外壳显示
  • 想加一个血条
  • 想加一条尾巴
  • 子弹想加一条尾巴
  • 子弹想加一个外壳

如果用继承,不灵活,装饰和被装饰者之间耦合度太高,类爆炸。

装饰者模式uml图聚合代替继承
装饰者模式uml图聚合代替继承

很多模式不是语法有区别,很多都是语义上有区别:比如桥梁模式是两个线独立发展,而装饰者模式是一个线的装饰设计=》两个设计都可以从依赖关系的设计拆解=》用代码依赖关系的实现即可。所以语法很像

6. 第八责任链ChainOfResponsibility

(相比Proxy和reator模式难度次着)

案例代码Filter

6-1. 问题

  • 在论坛中发表文章
  • 后台经过信息处理才可以发表或者进入数据库
  1. /** 
  2. * create-date:2022/6/28 
  3. * author:guojia.ma 
  4. * 责任链模式 
  5. * 封装就是封装变化 
  6. */ 
  7. public class Main { 
  8. public static void main(String[] args) { 
  9. Msg msg = new Msg(); 
  10. msg.setMsg("大家好:),<script>,欢迎访问top.guojia,大家都是996 "); 
  11. // 处理msg 
  12. /* String r = msg.getMsg(); 
  13. r=r.replace('<','['); 
  14. r=r.replace('>',']'); 
  15. r=r.replaceAll("996","955"); 
  16. msg.setMsg(r); 
  17. System.out.println(msg);*/ 
  18. /* new HTMLFilter().doFilter(msg); 
  19. new SensitiveFilter().doFilter(msg); 
  20. System.out.println(msg);*/ 
  21. // 把filter用list串起来 
  22. /* ArrayList<Filter> filters = new ArrayList<>(); 
  23. filters.add(new HTMLFilter()); 
  24. filters.add(new SensitiveFilter()); 
  25. for (Filter f:filters 
  26. ) { 
  27. f.doFilter(msg); 
  28. } 
  29. System.out.println(msg);*/ 
  30.  
  31. FilterChain fc=new FilterChain(); 
  32. /* fc.add(new HTMLFilter()); 
  33. fc.add(new SensitiveFilter());//add方法变函数式方式,fc的add实现增加返回值*/ 
  34. fc.add(new HTMLFilter()).add(new SensitiveFilter()); 
  35. // fc.doFilter(msg); 
  36. // System.out.println(msg); 
  37. // 两条链进行关联 
  38. FilterChain fc2 = new FilterChain(); 
  39. fc2.add(new FaceFilter()); 
  40. fc.add(fc2); 
  41. fc.doFilter(msg); 
  42. System.out.println(msg); 
  43. } 
  44.  
  45. } 
  46.  
  47. class Msg { 
  48. String name; 
  49. String msg; 
  50.  
  51. public String getName() { 
  52. return name; 
  53. } 
  54.  
  55. public void setName(String name) { 
  56. this.name = name; 
  57. } 
  58.  
  59. public String getMsg() { 
  60. return msg; 
  61. } 
  62.  
  63. public void setMsg(String msg) { 
  64. this.msg = msg; 
  65. } 
  66.  
  67. @Override 
  68. public String toString() { 
  69. return "Msg{" + 
  70. "name='" + name + '\'' + 
  71. ", msg='" + msg + '\'' + 
  72. '}'; 
  73. } 
  74. } 
  75. /*interface Filter{ 
  76. void doFilter(Msg m); 
  77. }*/ 
  78. /*每個filter是否继续执行的判断*/ 
  79. interface Filter{ 
  80. boolean doFilter(Msg m); 
  81. } 
  82. class HTMLFilter implements Filter{ 
  83.  
  84. @Override 
  85. public boolean doFilter(Msg m) { 
  86. String r = m.getMsg(); 
  87. r=r.replace('<','['); 
  88. r=r.replace('>',']'); 
  89. m.setMsg(r); 
  90. return true; 
  91. } 
  92. } 
  93.  
  94. class SensitiveFilter implements Filter{ 
  95.  
  96. @Override 
  97. public boolean doFilter(Msg m) { 
  98. String r = m.getMsg(); 
  99. r=r.replaceAll("996","955"); 
  100. m.setMsg(r); 
  101. return false;//如果出现敏感词就责任链往下停止执行 
  102. } 
  103. } 
  104.  
  105. class FaceFilter implements Filter{ 
  106.  
  107. @Override 
  108. public boolean doFilter(Msg m) { 
  109. String r = m.getMsg().replace(":)", "^v^"); 
  110. m.setMsg(r); 
  111. return true; 
  112. } 
  113. } 
  114.  
  115. /* 
  116. class FilterChain{ 
  117. List<Filter> filters=new ArrayList<>(); 
  118. */ 
  119. /* public void add(Filter f){ 
  120. filters.add(f); 
  121. }*//* 
  122.  
  123. public FilterChain add(Filter f){ 
  124. filters.add(f); 
  125. return this; 
  126. } 
  127.  
  128. public void doFilter(Msg m){ 
  129. for (Filter f:filters 
  130. ) { 
  131. f.doFilter(m); 
  132. } 
  133. } 
  134.  
  135. }*/ 
  136. class FilterChain implements Filter{ 
  137. List<Filter> filters=new ArrayList<>(); 
  138. /* public void add(Filter f){ 
  139. filters.add(f); 
  140. }*/ 
  141. public FilterChain add(Filter f){ 
  142. filters.add(f); 
  143. return this; 
  144. } 
  145. @Override 
  146. public boolean doFilter(Msg m){ 
  147. for (Filter f:filters 
  148. ) { 
  149. if(!f.doFilter(m)){return false;} 
  150. } 
  151. return true; 
  152. } 
  153. } 

责任链filter经典request,response的往回传链条

7. 第九Observer观察者(事件处理)

问题:小朋友睡醒哭,饿。

  1. /** 
  2. * create-date:2022/6/28 
  3. * author:guojia.ma 
  4. * * 抽出事件,观察者的源(被观察者) 
  5. * * 观察者的行为与被观察者及其事件类型是多对多关系 
  6. */ 
  7. class Child{ 
  8. private boolean cry=false; 
  9. private List<Observer> observers=new ArrayList<>(); 
  10. { 
  11. observers.add(new Dad()); 
  12. observers.add(new Mum()); 
  13. observers.add(new Dog()); 
  14. } 
  15.  
  16. public boolean isCry(){return cry;} 
  17. public void wakeUp(){ 
  18. cry=true; 
  19. WakeUpEvent event = new WakeUpEvent(System.currentTimeMillis(), "bed",this); 
  20. for (Observer o: observers 
  21. ) { 
  22. o.actionOnWakeUp(event); 
  23. } 
  24. } 
  25. } 
  26. abstract class Event<T>{ 
  27. abstract T getSource(); 
  28. } 
  29.  
  30. //事件类,fire event 
  31. class WakeUpEvent extends Event<Child>{ 
  32. long timestamp; 
  33. String loc;//location 
  34. Child source; 
  35. public WakeUpEvent(long timestamp, String loc, Child source){ 
  36. this.timestamp=timestamp; 
  37. this.loc=loc; 
  38. this.source=source; 
  39. } 
  40.  
  41. @Override 
  42. Child getSource() { 
  43. return source; 
  44. } 
  45. } 
  46. interface Observer{ 
  47. void actionOnWakeUp(WakeUpEvent event); 
  48. } 
  49. class Dad implements Observer { 
  50. public void feed(){ 
  51. System.out.println("dad feeding.."); 
  52. } 
  53.  
  54. @Override 
  55. public void actionOnWakeUp(WakeUpEvent event) { 
  56. feed(); 
  57. } 
  58. } 
  59. class Mum implements Observer { 
  60. public void hug(){ 
  61. System.out.println("Mum hug.."); 
  62. } 
  63.  
  64. @Override 
  65. public void actionOnWakeUp(WakeUpEvent event) { 
  66. hug(); 
  67. } 
  68. } 
  69. class Dog implements Observer { 
  70. public void wang(){ 
  71. System.out.println("dog wang.."); 
  72. } 
  73.  
  74. @Override 
  75. public void actionOnWakeUp(WakeUpEvent event) { 
  76. wang(); 
  77. } 
  78. } 
  79. public class Main { 
  80. public static void main(String[] args) { 
  81. Child c=new Child(); 
  82. c.wakeUp(); 
  83. } 
  84. } 

观察者模式类图
观察者模式类图

Observer,Listener,Hook,Callback都是观察者

在很多系统中,Observer模式往往和责任链工程负责对于事件的处理,其中的某一个observer负责是否将事件进一步传递;所以看见event也多是观察者模式有以上几个观察者的关键字标识。

观察者的模式用在责任链中一般没有往回传的链处理。

8. 第十组合Composite

树状结构专用模式

组合模式uml
组合模式uml

  1. abstract class Node{ 
  2. abstract public void p(); 
  3. } 
  4. class leafNode extends Node{ 
  5. String content; 
  6. public leafNode(String content){this.content=content;} 
  7.  
  8. @Override 
  9. public void p() { 
  10. System.out.println(content); 
  11. } 
  12. } 
  13. class BranchNode extends Node{ 
  14. List<Node> nodes=new ArrayList<>(); 
  15. String name; 
  16. public BranchNode(String name){this.name=name;} 
  17.  
  18. @Override 
  19. public void p() { 
  20. System.out.println(name); 
  21. } 
  22. public void add(Node n){ 
  23. nodes.add(n); 
  24. } 
  25. } 
  26. public class Main { 
  27. public static void main(String[] args) { 
  28. // tree(root); 
  29. } 
  30. static void tree(Node b,int depth){ 
  31. for (int i = 0; i < depth; i++) { 
  32. System.out.print("--"); 
  33. } 
  34. b.p(); 
  35. if(b instanceof BranchNode){ 
  36. for (Node n: ((BranchNode) b).nodes 
  37. ) { 
  38. tree(n,depth+1); 
  39. } 
  40. } 
  41. } 
  42. } 

9. 第11flyweight(享元)

重复利用对象

享元共享元数据对象比如字母a-z26个最大池子26uml图
享元共享元数据对象比如字母a-z26个最大池子26uml图

  1. class Bullet{ 
  2. public UUID id= UUID.randomUUID(); 
  3. boolean living=true; 
  4.  
  5. @Override 
  6. public String toString() { 
  7. return "Bullet{" + 
  8. "id=" + id + 
  9. ", living=" + living + 
  10. '}'; 
  11. } 
  12. } 
  13. public class BulletPool { 
  14. List<Bullet> bullets=new ArrayList<>(); 
  15. { 
  16. for (int i = 0; i < 5; i++) { 
  17. bullets.add(new Bullet()); 
  18. } 
  19. } 
  20. public Bullet getBullet(){ 
  21. for (int i = 0; i < bullets.size(); i++) { 
  22. Bullet bullet = bullets.get(i); 
  23. if(!bullet.living){return bullet;}; 
  24. } 
  25. return new Bullet(); 
  26. } 
  27.  
  28. public static void main(String[] args) { 
  29. BulletPool bp=new BulletPool(); 
  30. for (int i = 0; i < 10; i++) { 
  31. Bullet b = bp.getBullet(); 
  32. System.out.println(b); 
  33. } 
  34. } 
  35. } 

组合式享元
组合式享元

10. 代理Proxy

  • 静态代理
  • 动态代理
  • Spring AOP

benchamark查找性能差的点的测试用词。

静态代理uml
静态代理uml

  1. /** 
  2. * create-date:2022/6/29 
  3. * author:guojia.ma 
  4. * 动态代理:时间计算,增加代理逻辑前后的处理方法 
  5. */ 
  6. public class Tank implements Movable{ 
  7. @Override 
  8. public void move() { 
  9. System.out.println("Tank moving clacla..."); 
  10. try { 
  11. Thread.sleep(new Random().nextInt(10000)); 
  12. } catch (InterruptedException e) { 
  13. e.printStackTrace(); 
  14. } 
  15. } 
  16.  
  17. public static void main(String[] args) { 
  18. Tank tank=new Tank(); 
  19. System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles","true");//生成代理类的字节码文件 
  20. //reflection 反射,类的二进制字节码落进内存,通过字节码分析类的属性和方法。 
  21. Movable m=(Movable) Proxy.newProxyInstance(Tank.class.getClassLoader()//被代理对象 
  22. , new Class[]{Movable.class},//代理对象实现的接口数组 tank.class.getInsterfaces(); 
  23. new TimeProxy(tank) //代理对象实现接口的代理逻辑 
  24. ); 
  25. m.move();//调用move方法走了代理逻辑invoke,这就是动态代理的神奇 
  26. } 
  27. } 
  28. class TimeProxy implements InvocationHandler{ 
  29. Movable m; 
  30. public TimeProxy(Movable m){this.m=m;} 
  31. public void before(){ 
  32. System.out.println("method start before.."); 
  33. } 
  34. public void after(){ 
  35. System.out.println("method end after..."); 
  36. } 
  37. // getClass.getMethods[]:第一个参数proxy就是代理对象即m 
  38. @Override 
  39. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
  40. // System.out.println("method " + method.getName() + "start.."); 
  41. before(); 
  42. Object o = method.invoke(m, args);//m就是被代理对象(即tank实现了movable) move方法返回是空值,o就是空值 
  43. // System.out.println("method " + method.getName() + "end!"); 
  44. after(); 
  45. return o; 
  46. } 
  47. } 
  48. interface Movable{ 
  49. void move(); 
  50. } 

动态代理的类文件:
代理文件字节码反编译

代理类字节码反编译后面部分
代理类字节码反编译后面部分

动态代理流程图上面是生成代理过程下面是调用代理过程
动态代理流程图上面是生成代理过程下面是调用代理过程

asm包是直接操作二进制字节码文件。

有了asm就不需要源码,这也是java是动态语言(运行时修改代码)的本质
所以只要符合class文件字节码存储要求,就可以跑在JVM上
kotlin,scala就是直接编译生成class文件跑在jvm里。JVM生态

动态代理asm生成文件代码跟踪
动态代理asm生成文件代码跟踪

10-1. jdk生成动态代理需要实现接口而有些不需要

  • 如Instrement(调琴)的方式(java自带)不需要实现接口,钩子函数拦截器在落内存中的时候直接修改二进制码(要求完全了解二进制码)比asm的api更加强大。
  • 还有cglib(底层是asm)生成要比jdk的反射生成简单很多:tank如果是final类不可以因为enhancer是继承tank(asm可以把final去掉)。

AOP:A就是Aspect 切

IOC+AOP
bean工厂+灵活装配+动态行为拼接,成就spring在java框架中的一哥位置

11. 13模式Iterator迭代器

容器及容器遍历场景

11-1. 需求

  • 构建动态扩展的容器
    • list.add()
  • 数组的实现
  • 链表的实现
    数组vs链表:插入,删除,随机访问,扩展

迭代器uml图
迭代器uml图

  1. public class ArrayList_<E> implements Collection_<E>{ 
  2. E[] objects =(E[])new Object[10]; 
  3. private int index=0; 
  4. @Override 
  5. public void add(E o) { 
  6. if(index==objects.length){ 
  7. E[] newObjects =(E[])new Object[this.objects.length * 2]; 
  8. System.arraycopy(objects,0,newObjects,0,objects.length); 
  9. objects=newObjects; 
  10. } 
  11. objects[index]=o; 
  12. index++; 
  13. } 
  14.  
  15. @Override 
  16. public int size() { 
  17. return index; 
  18. } 
  19.  
  20. @Override 
  21. public Iterator_<E> iterator() { 
  22. return new ArrayListIterator(); 
  23. } 
  24.  
  25. private class ArrayListIterator implements Iterator_<E>{ 
  26. private int currentIndex=0; 
  27. @Override 
  28. public boolean hasNext() { 
  29. if(currentIndex>=index){return false;} 
  30. return true; 
  31. } 
  32.  
  33. @Override 
  34. public E next() { 
  35. E o = objects[currentIndex]; 
  36. currentIndex++; 
  37. return o; 
  38. } 
  39. } 
  40. } 
  41. public interface Collection_<E> { 
  42. void add(E o); 
  43. int size(); 
  44.  
  45. Iterator_<E> iterator(); 
  46. } 
  47. public interface Iterator_<E> { 
  48. boolean hasNext(); 
  49. E next(); 
  50. } 
  51. /** 
  52. * create-date:2022/6/29 
  53. * author:guojia.ma 
  54. * 链表的迭代器实现简版 
  55. */ 
  56. public class ListkedList_<E> implements Collection_<E>{ 
  57. Node head=null; 
  58. Node tail=null; 
  59. //目前容器中有多少个元素 
  60. private int size=0; 
  61.  
  62. private class Node<E>{ 
  63. private E o; 
  64. Node next; 
  65. public Node(E o){this.o=o;} 
  66. } 
  67.  
  68. @Override 
  69. public void add(E o) { 
  70. Node n=new Node(o); 
  71. n.next=null; 
  72. if(head==null){ 
  73. head=n; 
  74. tail=n; 
  75. } 
  76. tail.next=n; 
  77. tail=n; 
  78. size++; 
  79. } 
  80.  
  81. @Override 
  82. public int size() { 
  83. return size; 
  84. } 
  85.  
  86. @Override 
  87. public Iterator_<E> iterator() { 
  88. return new LinkedListIterator(head); 
  89. } 
  90.  
  91. private class LinkedListIterator<E> implements Iterator_<E>{ 
  92. private Node next; 
  93. private int index=0; 
  94. public LinkedListIterator(Node head){ 
  95. // assert isPositionIndex(index); 
  96. this.next=head; 
  97. } 
  98.  
  99. @Override 
  100. public boolean hasNext() { 
  101. if(index>=size){return false;} 
  102. return true; 
  103. } 
  104.  
  105. @Override 
  106. public E next() { 
  107. E n=null; 
  108. if(hasNext()){ 
  109. next = this.next.next; 
  110. n=(E) next.o; 
  111. index++; 
  112. return n; 
  113. } 
  114. return null; 
  115. } 
  116.  
  117. } 
  118. } 
  119. public class Main { 
  120. public static void main(String[] args) { 
  121. Collection_<String> list = new ListkedList_<>(); 
  122. for (int i = 0; i < 15; i++) { 
  123. list.add(new String("s"+i)); 
  124. } 
  125. System.out.println(list.size()); 
  126. /* Collection c = new LinkedList(); 
  127. for (int i = 0; i < 15; i++) { 
  128. c.add(new String("s"+i)); 
  129. }*/ 
  130. // System.out.println(c.size()); 
  131. Iterator_<String> it=list.iterator(); 
  132. // Iterator it = c.iterator(); 
  133. while(it.hasNext()){ 
  134. String o = it.next(); 
  135. System.out.println(o); 
  136. } 
  137. } 
  138. } 

12. 14访问者visitor

在结构不变的情况下动态改变对于内部元素的动作。

  1. package top.guojia.mode.visitor; 
  2.  
  3. /** 
  4. * create-date:2022/6/29 
  5. * author:guojia.ma 
  6. * 观察者模式 
  7. */ 
  8. public class Computer { 
  9. ComputerPart cpu=new Cpu(); 
  10. ComputerPart memory=new Memory(); 
  11. ComputerPart board=new Board(); 
  12. public void accept(Visitor v){ 
  13. this.cpu.accept(v);//接待来访者 
  14. this.memory.accept(v); 
  15. this.board.accept(v); 
  16. } 
  17. public static void main(String[] args) { 
  18. PersonelVisitor p=new PersonelVisitor(); 
  19. new Computer().accept(p); 
  20. System.out.println(p.totalPrice); 
  21. } 
  22. } 
  23. abstract class ComputerPart{ 
  24. abstract void accept(Visitor v); 
  25. abstract double getPrice(); 
  26. } 
  27. class Cpu extends ComputerPart{ 
  28.  
  29. @Override 
  30. void accept(Visitor v) { 
  31. v.visitCpu(this); 
  32. } 
  33.  
  34. @Override 
  35. double getPrice() { 
  36. return 500; 
  37. } 
  38. } 
  39.  
  40. class Memory extends ComputerPart{ 
  41.  
  42. @Override 
  43. void accept(Visitor v) { 
  44. v.visitMemory(this); 
  45. } 
  46.  
  47. @Override 
  48. double getPrice() { 
  49. return 300; 
  50. } 
  51. } 
  52. class Board extends ComputerPart{ 
  53.  
  54. @Override 
  55. void accept(Visitor v) { 
  56. v.visitBoard(this); 
  57. } 
  58.  
  59. @Override 
  60. double getPrice() { 
  61. return 100; 
  62. } 
  63. } 
  64.  
  65. interface Visitor{ 
  66. void visitCpu(Cpu cpu); 
  67. void visitMemory(Memory memory); 
  68. void visitBoard(Board board); 
  69. } 
  70.  
  71. class PersonelVisitor implements Visitor{//个人类型的来访者 
  72. double totalPrice=0.0; 
  73. @Override 
  74. public void visitCpu(Cpu cpu) { 
  75. totalPrice+=cpu.getPrice()*0.9; 
  76. } 
  77.  
  78. @Override 
  79. public void visitMemory(Memory memory) { 
  80. totalPrice+=memory.getPrice()*0.85; 
  81. } 
  82.  
  83. @Override 
  84. public void visitBoard(Board board) { 
  85. totalPrice+=board.getPrice()*0.95; 
  86. } 
  87. } 
  88. class CorpVisitor implements Visitor{ 
  89. double totalPrice=0.0; 
  90. @Override 
  91. public void visitCpu(Cpu cpu) { 
  92. totalPrice+=cpu.getPrice()*0.8; 
  93. } 
  94.  
  95. @Override 
  96. public void visitMemory(Memory memory) { 
  97. totalPrice+=memory.getPrice()*0.8; 
  98. } 
  99.  
  100. @Override 
  101. public void visitBoard(Board board) { 
  102. totalPrice+=board.getPrice()*0.8; 
  103. } 
  104. } 

访问者模式只针对结构固定的可以让访问者访问固定的结构,结构接受访问。

访问者模式的一种场景
访问者模式的一种场景

访问类图operator被访问的节点的操作
访问类图operator被访问的节点的操作

12-1. ASM

classfile的数据信息
classfile的数据信息

如果了解每个字节什么意思,应该读JAVA虚拟机规范。

JAVAP反编译class文件用汇编的方式展示

如图在idea view菜单也可以用jclasslib插件
如图在idea view菜单也可以用jclasslib插件

  1. /** 
  2. * create-date:2022/6/29 
  3. * author:guojia.ma 
  4. * asm反编译javap底层逻辑:打印反编译内容的部分信息 
  5. */ 
  6. public class ClassPrinter extends ClassVisitor { 
  7. public ClassPrinter(){super(ASM4);} 
  8. @Override 
  9. public void visit(int version,int access,String name,String signature,String superName,String[] interfaces){ 
  10. System.out.println(name + " extends " + superName + "{"); 
  11. } 
  12. @Override 
  13. public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value){ 
  14. System.out.println(" " + name); 
  15. return null; 
  16. } 
  17.  
  18. @Override 
  19. public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions){ 
  20. System.out.println(" " + name + "()"); 
  21. return null; 
  22. } 
  23. @Override 
  24. public void visitEnd(){ 
  25. System.out.println("}"); 
  26. } 
  27.  
  28. public static void main(String[] args) throws IOException { 
  29. ClassPrinter cp = new ClassPrinter();//访问者 
  30. ClassReader cr=new ClassReader("java.lang.Runnable");//被访问者 
  31. cr.accept(cp,0); 
  32. } 
  33. } 
  34. //--写字节码文件 
  35. /** 
  36. * create-date:2022/6/29 
  37. * author:guojia.ma 
  38. * 写出字节码信息 
  39. */ 
  40. public class ClassWriteTest { 
  41. public static void main(String[] args) { 
  42. ClassWriter cw = new ClassWriter(0); 
  43. cw.visit(V1_5,ACC_PUBLIC+ACC_ABSTRACT+ACC_INTERFACE, 
  44. "pkg/Comparable",null,"java/lang/Object",null); 
  45. cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC,"LESS","I",null,-1).visitEnd(); 
  46. cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC,"EQUAL","I",null,0).visitEnd(); 
  47. cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC,"GREATER","I",null,1).visitEnd(); 
  48. cw.visitMethod(ACC_PUBLIC+ACC_ABSTRACT,"compareTo","(Ljava/lang/Object;)I",null,null).visitEnd(); 
  49. cw.visitEnd(); 
  50. byte[] b = cw.toByteArray(); 
  51. MyClassLoader myClassLoader=new MyClassLoader(); 
  52. Class c=myClassLoader.defineClass("pkg.Comparable",b); 
  53. System.out.println(c.getMethods()[0].getName()); 
  54. } 
  55. public class MyClassLoader extends ClassLoader{ 
  56. public Class defineClass(String name,byte[] b){return defineClass(name,b,0,b.length);} 
  57. } 

12-2. 使用asm做动态代理的案例

  1. /** 
  2. * create-date:2022/6/29 
  3. * author:guojia.ma 
  4. * 使用asm做动态代理 
  5. */ 
  6. public class ClassTransformerTest { 
  7. public static void main(String[] args) throws Exception { 
  8. ClassReader cr=new ClassReader(ClassPrinter.class.getClassLoader().getResourceAsStream("top/guojia/mode/visitor/asm/Tank.class")); 
  9. ClassWriter cw = new ClassWriter(0); 
  10. ClassVisitor cv=new ClassVisitor(ASM4,cw){ 
  11. @Override 
  12. public MethodVisitor visitMethod(int access,String name,String descriptor,String signature,String[] exceptions){ 
  13. MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 
  14. //returen mv 
  15. return new MethodVisitor(ASM4,mv) { 
  16. @Override 
  17. public void visitCode() { 
  18. visitMethodInsn(INVOKESTATIC,"TimeProxy","before","()V",false); 
  19. super.visitCode(); 
  20. } 
  21. }; 
  22. } 
  23. }; 
  24. cr.accept(cv,0);//cr里是cv,cv里是cw形成一个链,cv就相当于访问了cr然后在修改cr的开始代码visitCode,在里面访问代理TimeProxy类的静态方法;然后cw访问新修改后cr的cv数据写到磁盘文件字节码文件 
  25. byte[] b = cw.toByteArray(); 
  26. String path =(String) System.getProperties().get("user.dir"); 
  27. File f = new File(path + "/top/guojia/mode/visitor/asm/"); 
  28. f.mkdirs(); 
  29. FileOutputStream fos= new FileOutputStream(new File(path+"/top/guojia/mode/visitor/asm/Tank_0.class")); 
  30. fos.write(b); 
  31. fos.flush(); 
  32. fos.close(); 
  33. } 
  34. } 

13. 15Builder

构造复杂对象。和模板方法非常像,不过这里是表示构建复杂对象。

13-1. 解析

  • 分离复杂对象的构建和表示
  • 同样的构建过程可以创建不同的表示
  • 无需记忆,自然使用。

builder类图
builder类图

  1. public class Person { 
  2. int id; 
  3. String name; 
  4. int age; 
  5. double weight; 
  6. int score; 
  7. Location loc; 
  8. private Person(){} 
  9. public static class PersionBuilder{ 
  10. Person p=new Person(); 
  11. public PersionBuilder basicInfo(int id,String name,int age){ 
  12. p.id=id; 
  13. p.name=name; 
  14. p.age=age; 
  15. return this; 
  16. } 
  17. public PersionBuilder weight(double weight){ 
  18. p.weight=weight; 
  19. return this; 
  20. } 
  21. public PersionBuilder score(int score){ 
  22. p.score=score; 
  23. return this; 
  24. } 
  25. public PersionBuilder loc(String street,String roomNo){ 
  26. p.loc=new Location(street,roomNo); 
  27. return this; 
  28. } 
  29. public Person build(){return p;} 
  30. } 
  31. } 
  32. class Location{ 
  33. String street; 
  34. String roomNo; 
  35. public Location(String street,String roomNo){ 
  36. this.street=street; 
  37. this.roomNo=roomNo; 
  38. } 
  39. } 

14. 16Adapter(Wrapper)

接口转换器:A-B不能直接访问加个转换。

类图图解
类图图解

  • 电压转接头
  • java.io
  • jdbc-odbc bridge(不是桥接模式)
  • ASM transformer
  1. public class Main { 
  2. public static void main(String[] args) { 
  3. FileInputStream fis = new FileInputStream("c:/test.text"); 
  4. InputStreamReader isr = new InputStreamReader(fis); 
  5. BufferedReader br = new BufferedReader(isr); 
  6. String line = br.readLine(); 
  7. while(line!=null&&line.equals("")){ 
  8. System.out.println(line); 
  9. } 
  10. br.close(); 
  11. } 
  12. } 

14-1. 误区:

  • 常见的Adapter类反而不是Adapter比如WindowAdapter,KeyAdapter

历史原因方便变成的一种方式叫的名字歧义而已
历史原因方便变成的一种方式叫的名字歧义而已

15. 17 Bridge

双维度扩展

图解类关系
图解类关系

15-1. 解析

  • 分离抽象和具体
  • 用聚合方式(桥)连接抽象与具体

15-1-1. 分三步实现:

  1. public class Book extends GiftImpl{ 
  2. } 
  3. public class Flower extends GiftImpl{ 
  4. } 
  5. public abstract class Gift { 
  6. GiftImpl impl;//1.在Gift里面聚合了实现;2.形容词+名词(WildGift的类继承这个名词带实现的抽象类Gift3.名词具体实体(Flower)从实现GiftImpl继承。 
  7. } 
  8. public class GiftImpl { 
  9. } 
  10. public class WarmGift extends Gift{ 
  11. public WarmGift(GiftImpl impl){ 
  12. this.impl=impl; 
  13. } 
  14. } 
  15. public class WildGift extends Gift{ 
  16. public WildGift(GiftImpl impl){ 
  17. this.impl=impl; 
  18. } 
  19. } 
  20. public class GG { 
  21. public void chase(MM mm){ 
  22. Gift g = new WarmGift(new Flower()); 
  23. give(mm,g); 
  24. } 
  25. public void give(MM mm, Gift g){ 
  26. System.out.println(g + "gived"); 
  27. } 
  28. } 

16. 18Command命令

  • 封装命令
  • 结合cor实现undo功能

16-1. 解析

  • 别名:Action/Transaction 动作/事务
  • 宏命令:command与?(组合composite)模式:好多命令组成
  • 多次undo:comand与?(cor)模式 多次undo
  • transaction回滚:command与?(memento)模式
  1. public abstract class Command { 
  2. public abstract void doit();//run, exec意思一样 
  3. public abstract void undo(); 
  4. } 
  5. public class Content { 
  6. String msg="hello everybody "; 
  7. } 
  8. public class InsertCommand extends Command{ 
  9. Content c; 
  10. String strToInsert="http://www.guojia.ma.top"; 
  11. public InsertCommand(Content c){ 
  12. this.c=c; 
  13. } 
  14. @Override 
  15. public void doit() { 
  16. c.msg=c.msg+strToInsert; 
  17. } 
  18.  
  19. @Override 
  20. public void undo() { 
  21. c.msg=c.msg.substring(0,c.msg.length()-strToInsert.length()); 
  22. } 
  23. } 
  24. public class Main 
  25. { 
  26. public static void main(String[] args) { 
  27. Content c=new Content(); 
  28. InsertCommand insertCommand = new InsertCommand(c); 
  29. insertCommand.doit(); 
  30. insertCommand.undo(); 
  31. System.out.println(c.msg); 
  32. } 
  33. } 

17. 19prototype原型模式

Object.clone()

图解原型模式
图解原型模式

17-1. java中的原型模式

  • 自带
  • 实现原型模式需要实现标记型接口Cloneable
  • 一般会重写clone方法
    • 如果只是重写clone方法而没实现接口,调用时会报异常(需要1.实现接口2重写clone方法)
    • 编译不报错,运行报错重写可以直接super.clone用Object系统native clone方法。
  • 一般用于一个对象的属性已经确定,需要产生很多相同对象的时候
  • 需要区分深克隆(引用类型需要再调用clone把引用的数据拷贝一份:字符串不需要如果是new串需要)与浅克隆(引用类型引用地址被拷贝)
  1. //深克隆 
  2. public class Test { 
  3. public static void main(String[] args) throws CloneNotSupportedException { 
  4. Person p1 = new Person(); 
  5. Person p2 =(Person)p1.clone(); 
  6. System.out.println(p2.age + " " + p2.score); 
  7. System.out.println(p2.loc); 
  8. System.out.println(p1.loc == p2.loc); 
  9. p1.loc.street="sh";//因为loc被深克隆所以p1,p2互不影响 
  10. System.out.println(p2.loc); 
  11. } 
  12. } 
  13.  
  14. class Person implements Cloneable{ 
  15. int age=8; 
  16. int score=100; 
  17.  
  18. Location loc=new Location("bj",22); 
  19. @Override 
  20. public Object clone() throws CloneNotSupportedException{ 
  21. Person p=(Person) super.clone(); 
  22. p.loc=(Location)loc.clone(); 
  23. return p; 
  24. } 
  25.  
  26. } 
  27.  
  28. class Location implements Cloneable{//没有可实现的方法所以快捷键不支持生成方法要手动实现clone的overwrite 
  29. String street; 
  30. int roomNo; 
  31. public Location(String street,int roomNo){ 
  32. this.street=street; 
  33. this.roomNo=roomNo; 
  34. } 
  35.  
  36. @Override 
  37. public String toString() { 
  38. return "Location{" + 
  39. "street='" + street + '\'' + 
  40. ", roomNo=" + roomNo + 
  41. '}'; 
  42. } 
  43. @Override 
  44. public Object clone() throws CloneNotSupportedException{ 
  45. return super.clone(); 
  46. } 
  47. } 

18. 20Memento(备忘录)与序列化

记录状态便于回滚。

18-1. 解析

  • 记录快照(瞬时状态)
  • 存盘

transient 透明的:序列化时丢弃对象

18-1-1. 实现序列化:

  • 实体类的父类:implenments Serializable
  • 接口:extends Serializable

代码案例流忘了关闭
代码案例流忘了关闭

19. 21模板TemplateMethod

钩子函数

图解
图解

19-1. 解析

其实一直在用

  • paint(Graphics g)
  • WindowListener
    • windowClosing()
    • windowXXX()
  • ASM
    • ClassVisitor
  1. public class Main { 
  2. public static void main(String[] args) { 
  3. F f=new C1(); 
  4. f.m(); 
  5. } 
  6. } 
  7. abstract class F{ 
  8. void m(){ 
  9. op1(); 
  10. op2(); 
  11. } 
  12. abstract void op1(); 
  13. abstract void op2(); 
  14. } 
  15. class C1 extends F{ 
  16.  
  17. @Override 
  18. void op1() { 
  19. System.out.println("op1"); 
  20. } 
  21.  
  22. @Override 
  23. void op2() { 
  24. System.out.println("op2"); 
  25. } 
  26. } 

20. 22State状态模式

根据状态决定行为

  1. public abstract class MMState { 
  2. abstract void smile(); 
  3. abstract void cry(); 
  4. abstract void say(); 
  5. } 
  6. public class MM { 
  7. String name; 
  8. MMState state; 
  9. public void smile(){ 
  10. state.smile(); 
  11. } 
  12. public void cry(){ 
  13. state.cry(); 
  14. } 
  15. public void say(){ 
  16. state.say(); 
  17. } 
  18. } 
  19. public class MMHappyState extends MMState{ 
  20.  
  21. @Override 
  22. void smile() { 
  23. System.out.println("HappySmile"); 
  24. } 
  25.  
  26. @Override 
  27. void cry() { 
  28.  
  29. } 
  30.  
  31. @Override 
  32. void say() { 
  33.  
  34. } 
  35. } 
  36. public class MMCryState extends MMState{ 
  37. @Override 
  38. void smile() { 
  39. System.out.println("苦中2带笑"); 
  40. } 
  41.  
  42. @Override 
  43. void cry() { 
  44.  
  45. } 
  46.  
  47. @Override 
  48. void say() { 
  49.  
  50. } 
  51. } 

图解
图解

client的opration不需要扩展适合用state模式,否则就要把所有state子类都要实现opration的扩展,代码耦合度太高。

有限状态机线程状态图
有限状态机线程状态图

21. 23Intepreter解释器

动态脚本解析

intepreter类图
intepreter类图

21-1. 解释器模式的结构

  • 抽象解释器:声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret()方法,称为解释操作。具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器TerminalExpression和非终结符解释器NonterminalExpression完成。
  • 终结符表达式:实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。终结符一半是文法中的运算单元,比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
  • 非终结符表达式:文法中的每条规则对应于一个非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,+就是非终结符,解析+的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。
  • 环境角色:这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。

21-2. 优缺点

  • 优:解释器是一个简单的语法分析工具,它最显著的优点就是扩展性,修改语法规则只需要修改相应的非终结符就可以了,若扩展语法,只需要增加非终结符类就可以了。

  • 缺:但是,解释器模式会引起类的膨胀,每个语法都需要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件;由于使用了大量的循环和递归,效率是一个不容忽视的问题。特别是用于解释一个解析复杂、冗长的语法时,效率是难以忍受的。

21-3. 代码

  1. //代碼還有報錯 
  2. class Context {} 
  3. abstract class Expression { 
  4. public abstract Object interpreter(Context ctx); 
  5. } 
  6. class TerminalExpression extends Expression { 
  7. public Object interpreter(Context ctx){ 
  8. return null; 
  9. } 
  10. } 
  11. class NonterminalExpression extends Expression { 
  12. public NonterminalExpression(Expression...expressions){ 
  13.  
  14. } 
  15. public Object interpreter(Context ctx){ 
  16. return null; 
  17. } 
  18. } 
  19. public class Client { 
  20. public static void main(String[] args){ 
  21. String expression = ""; 
  22. char[] charArray = expression.toCharArray(); 
  23. Context ctx = new Context(); 
  24. Stack stack = new Stack(); 
  25. for(int i=0;i<5;i++) { 
  26. //进行语法判断,递归调用 
  27. } 
  28. } 
  29. Expression exp = stack.pop(); 
  30. exp.interpreter(ctx); 
  31. } 
  32. } 

模式分类
模式分类

指导思想
指导思想

posted @ 2022-07-01 13:48  编程未来  阅读(505)  评论(0编辑  收藏  举报