当前位置: 首页 > news >正文

网站建设展示型是什么国外外包网站

网站建设展示型是什么,国外外包网站,做网站要学的东西,改图网站5#xff0c;结构型模式 5.6 组合模式 5.6.1 概述 对于这个图片肯定会非常熟悉#xff0c;上图我们可以看做是一个文件系统#xff0c;对于这样的结构我们称之为树形结构。在树形结构中可以通过调用某个方法来遍历整个树#xff0c;当我们找到某个叶子节点后#xff0c;…5结构型模式 5.6 组合模式 5.6.1 概述 对于这个图片肯定会非常熟悉上图我们可以看做是一个文件系统对于这样的结构我们称之为树形结构。在树形结构中可以通过调用某个方法来遍历整个树当我们找到某个叶子节点后就可以对叶子节点进行相关的操作。可以将这颗树理解成一个大的容器容器里面包含很多的成员对象这些成员对象即可是容器对象也可以是叶子对象。但是由于容器对象和叶子对象在功能上面的区别使得我们在使用的过程中必须要区分容器对象和叶子对象但是这样就会给客户带来不必要的麻烦作为客户而已它始终希望能够一致的对待容器对象和叶子对象。 定义 ​ 又名部分整体模式是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象用来表示部分以及整体层次。这种类型的设计模式属于结构型模式它创建了对象组的树形结构。 5.6.2 结构 组合模式主要包含三种角色 抽象根节点Component定义系统各层次对象的共有方法和属性可以预先定义一些默认行为和属性。树枝节点Composite定义树枝节点的行为存储子节点组合树枝节点和叶子节点形成一个树形结构。叶子节点Leaf叶子节点对象其下再无分支是系统层次遍历的最小单位。 5.6.3 案例实现 【例】软件菜单 如下图我们在访问别的一些管理系统时经常可以看到类似的菜单。一个菜单可以包含菜单项菜单项是指不再包含其他内容的菜单条目也可以包含带有其他菜单项的菜单因此使用组合模式描述菜单就很恰当我们的需求是针对一个菜单打印出其包含的所有菜单以及菜单项的名称。 要实现该案例我们先画出类图 代码实现 不管是菜单还是菜单项都应该继承自统一的接口这里姑且将这个统一的接口称为菜单组件。 //菜单组件 不管是菜单还是菜单项都应该继承该类 public abstract class MenuComponent {protected String name;protected int level;//添加菜单public void add(MenuComponent menuComponent){throw new UnsupportedOperationException();}//移除菜单public void remove(MenuComponent menuComponent){throw new UnsupportedOperationException();}//获取指定的子菜单public MenuComponent getChild(int i){throw new UnsupportedOperationException();}//获取菜单名称public String getName(){return name;}public void print(){throw new UnsupportedOperationException();} } 这里的MenuComponent定义为抽象类因为有一些共有的属性和行为要在该类中实现Menu和MenuItem类就可以只覆盖自己感兴趣的方法而不用搭理不需要或者不感兴趣的方法举例来说Menu类可以包含子菜单因此需要覆盖add()、remove()、getChild()方法但是MenuItem就不应该有这些方法。这里给出的默认实现是抛出异常你也可以根据自己的需要改写默认实现。 public class Menu extends MenuComponent {private ListMenuComponent menuComponentList;public Menu(String name,int level){this.level level;this.name name;menuComponentList new ArrayListMenuComponent();}Overridepublic void add(MenuComponent menuComponent) {menuComponentList.add(menuComponent);}Overridepublic void remove(MenuComponent menuComponent) {menuComponentList.remove(menuComponent);}Overridepublic MenuComponent getChild(int i) {return menuComponentList.get(i);}Overridepublic void print() {for (int i 1; i level; i) {System.out.print(--);}System.out.println(name);for (MenuComponent menuComponent : menuComponentList) {menuComponent.print();}} } Menu类已经实现了除了getName方法的其他所有方法因为Menu类具有添加菜单移除菜单和获取子菜单的功能。 public class MenuItem extends MenuComponent {public MenuItem(String name,int level) {this.name name;this.level level;}Overridepublic void print() {for (int i 1; i level; i) {System.out.print(--);}System.out.println(name);} } MenuItem是菜单项不能再有子菜单所以添加菜单移除菜单和获取子菜单的功能并不能实现。 5.6.4 组合模式的分类 在使用组合模式时根据抽象构件类的定义形式我们可将组合模式分为透明组合模式和安全组合模式两种形式。 透明组合模式 透明组合模式中抽象根节点角色中声明了所有用于管理成员对象的方法比如在示例中 MenuComponent 声明了 add、remove 、getChild 方法这样做的好处是确保所有的构件类都有相同的接口。透明组合模式也是组合模式的标准形式。 透明组合模式的缺点是不够安全因为叶子对象和容器对象在本质上是有区别的叶子对象不可能有下一个层次的对象即不可能包含成员对象因此为其提供 add()、remove() 等方法是没有意义的这在编译阶段不会出错但在运行阶段如果调用这些方法可能会出错如果没有提供相应的错误处理代码 安全组合模式 在安全组合模式中在抽象构件角色中没有声明任何用于管理成员对象的方法而是在树枝节点 Menu 类中声明并实现这些方法。安全组合模式的缺点是不够透明因为叶子构件和容器构件具有不同的方法且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义因此客户端不能完全针对抽象编程必须有区别地对待叶子构件和容器构件。 ![](file://D:\work\资料-ja va设计模式图解框架源码分析实战\Java设计模式资料day04\笔记\img\组合模式-安全性.png?msec1680705231183) 5.6.5 优点 组合模式可以清楚地定义分层次的复杂对象表示对象的全部或部分层次它让客户端忽略了层次的差异方便对整个层次结构进行控制。客户端可以一致地使用一个组合结构或其中单个对象不必关心处理的是单个对象还是整个组合结构简化了客户端代码。在组合模式中增加新的树枝节点和叶子节点都很方便无须对现有类库进行任何修改符合“开闭原则”。组合模式为树形结构的面向对象实现提供了一种灵活的解决方案通过叶子节点和树枝节点的递归组合可以形成复杂的树形结构但对树形结构的控制却非常简单。 5.6.6 使用场景 组合模式正是应树形结构而生所以组合模式的使用场景就是出现树形结构的地方。比如文件目录显示多级目录呈现等树形结构数据的操作。 5.7 享元模式 5.7.1 概述 定义 ​ 运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似对象的开销从而提高系统资源的利用率。 5.7.2 结构 享元Flyweight 模式中存在以下两种状态 内部状态即不会随着环境的改变而改变的可共享部分。外部状态指随环境改变而改变的不可以共享的部分。享元模式的实现要领就是区分应用中的这两种状态并将外部状态外部化。 享元模式的主要有以下角色 抽象享元角色Flyweight通常是一个接口或抽象类在抽象享元类中声明了具体享元类公共的方法这些方法可以向外界提供享元对象的内部数据内部状态同时也可以通过这些方法来设置外部数据外部状态。具体享元Concrete Flyweight角色 它实现了抽象享元类称为享元对象在具体享元类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类为每一个具体享元类提供唯一的享元对象。非享元Unsharable Flyweight)角色 并不是所有的抽象享元类的子类都需要被共享不能被共享的子类可设计为非共享具体享元类当需要一个非共享具体享元类的对象时可以直接通过实例化创建。享元工厂Flyweight Factory角色 负责创建和管理享元角色。当客户对象请求一个享元对象时享元工厂检査系统中是否存在符合要求的享元对象如果存在则提供给客户如果不存在的话则创建一个新的享元对象。 5.7.3 案例实现 【例】俄罗斯方块 下面的图片是众所周知的俄罗斯方块中的一个个方块如果在俄罗斯方块这个游戏中每个不同的方块都是一个实例对象这些对象就要占用很多的内存空间下面利用享元模式进行实现。 ![](file://D:\work\资料-ja va设计模式图解框架源码分析实战\Java设计模式资料day04\笔记\img\俄罗斯方块.jpeg?msec1680705231184) 先来看类图 ![](file://D:\work\资料-ja va设计模式图解框架源码分析实战\Java设计模式资料day04\笔记\img\享元模式.png?msec1680705231184) 代码如下 俄罗斯方块有不同的形状我们可以对这些形状向上抽取出AbstractBox用来定义共性的属性和行为。 public abstract class AbstractBox {public abstract String getShape();public void display(String color) {System.out.println(方块形状 this.getShape() 颜色 color);} } 接下来就是定义不同的形状了IBox类、LBox类、OBox类等。 public class IBox extends AbstractBox {Overridepublic String getShape() {return I;} }public class LBox extends AbstractBox {Overridepublic String getShape() {return L;} }public class OBox extends AbstractBox {Overridepublic String getShape() {return O;} } 提供了一个工厂类BoxFactory用来管理享元对象也就是AbstractBox子类对象该工厂类对象只需要一个所以可以使用单例模式。并给工厂类提供一个获取形状的方法。 public class BoxFactory {private static HashMapString, AbstractBox map;private BoxFactory() {map new HashMapString, AbstractBox();AbstractBox iBox new IBox();AbstractBox lBox new LBox();AbstractBox oBox new OBox();map.put(I, iBox);map.put(L, lBox);map.put(O, oBox);}public static final BoxFactory getInstance() {return SingletonHolder.INSTANCE;}private static class SingletonHolder {private static final BoxFactory INSTANCE new BoxFactory();}public AbstractBox getBox(String key) {return map.get(key);} } 5.7.5 优缺点和使用场景 1优点 极大减少内存中相似或相同对象数量节约系统资源提供系统性能享元模式中的外部状态相对独立且不影响内部状态 2缺点 为了使对象可以共享需要将享元对象的部分状态外部化分离内部状态和外部状态使程序逻辑复杂 3使用场景 一个系统有大量相同或者相似的对象造成内存的大量耗费。对象的大部分状态都可以外部化可以将这些外部状态传入对象中。在使用享元模式时需要维护一个存储享元对象的享元池而这需要耗费一定的系统资源因此应当在需要多次重复使用享元对象时才值得使用享元模式。 5.7.6 JDK源码解析 Integer类使用了享元模式。我们先看下面的例子 public class Demo {public static void main(String[] args) {Integer i1 127;Integer i2 127;System.out.println(i1和i2对象是否是同一个对象 (i1 i2));Integer i3 128;Integer i4 128;System.out.println(i3和i4对象是否是同一个对象 (i3 i4));} } 运行上面代码结果如下 ![](file://D:\work\资料-ja va设计模式图解框架源码分析实战\Java设计模式资料day04\笔记\img\image-20200208212930857.png?msec1680705231184) 为什么第一个输出语句输出的是true第二个输出语句输出的是false通过反编译软件进行反编译代码如下 public class Demo {public static void main(String[] args) {Integer i1 Integer.valueOf((int)127);Integer i2 Integer.valueOf((int)127);System.out.println((String)new StringBuilder().append((String)i1\u548ci2\u5bf9\u8c61\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1f).append((boolean)(i1 i2)).toString());Integer i3 Integer.valueOf((int)128);Integer i4 Integer.valueOf((int)128);System.out.println((String)new StringBuilder().append((String)i3\u548ci4\u5bf9\u8c61\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1f).append((boolean)(i3 i4)).toString());} } 上面代码可以看到直接给Integer类型的变量赋值基本数据类型数据的操作底层使用的是 valueOf() 所以只需要看该方法即可 public final class Integer extends Number implements ComparableInteger {public static Integer valueOf(int i) {if (i IntegerCache.low i IntegerCache.high)return IntegerCache.cache[i (-IntegerCache.low)];return new Integer(i);}private static class IntegerCache {static final int low -128;static final int high;static final Integer cache[];static {int h 127;String integerCacheHighPropValue sun.misc.VM.getSavedProperty(java.lang.Integer.IntegerCache.high);if (integerCacheHighPropValue ! null) {try {int i parseInt(integerCacheHighPropValue);i Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {}}high h;cache new Integer[(high - low) 1];int j low;for(int k 0; k cache.length; k)cache[k] new Integer(j);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high 127;}private IntegerCache() {}} } 可以看到 Integer 默认先创建并缓存 -128 ~ 127 之间数的 Integer 对象当调用 valueOf 时如果参数在 -128 ~ 127 之间则计算下标并从缓存中返回否则创建一个新的 Integer 对象。 6行为型模式 行为型模式用于描述程序在运行时复杂的流程控制即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式前者采用继承机制来在类间分派行为后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低满足“合成复用原则”所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为 模板方法模式策略模式命令模式职责链模式状态模式观察者模式中介者模式迭代器模式访问者模式备忘录模式解释器模式 以上 11 种行为型模式除了模板方法模式和解释器模式是类行为型模式其他的全部属于对象行为型模式。 6.1 模板方法模式 6.1.1 概述 在面向对象程序设计过程中程序员常常会遇到这种情况设计一个系统时知道了算法所需的关键步骤而且确定了这些步骤的执行顺序但某些步骤的具体实现还未知或者说某些步骤的实现与具体的环境相关。 例如去银行办理业务一般要经过以下4个流程取号、排队、办理具体业务、对银行工作人员进行评分等其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的可以在父类中实现但是办理具体业务却因人而异它可能是存款、取款或者转账等可以延迟到子类中实现。 定义 定义一个操作中的算法骨架而将算法的一些步骤延迟到子类中使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。 6.1.2 结构 模板方法Template Method模式包含以下主要角色 抽象类Abstract Class负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。 模板方法定义了算法的骨架按某种顺序调用其包含的基本方法。 基本方法是实现算法各个步骤的方法是模板方法的组成部分。基本方法又可以分为三种 抽象方法(Abstract Method) 一个抽象方法由抽象类声明、由其具体子类实现。 具体方法(Concrete Method) 一个具体方法由一个抽象类或具体类声明并实现其子类可以进行覆盖也可以直接继承。 钩子方法(Hook Method) 在抽象类中已经实现包括用于判断的逻辑方法和需要子类重写的空方法两种。 一般钩子方法是用于判断的逻辑方法这类方法名一般为isXxx返回值类型为boolean类型。 具体子类Concrete Class实现抽象类中所定义的抽象方法和钩子方法它们是一个顶级逻辑的组成步骤。 6.1.3 案例实现 【例】炒菜 炒菜的步骤是固定的分为倒油、热油、倒蔬菜、倒调料品、翻炒等步骤。现通过模板方法模式来用代码模拟。类图如下 ![](file://D:\work\资料-ja va设计模式图解框架源码分析实战\Java设计模式资料day04\笔记\img\模板方法模式.png?msec1680705231184) 代码如下 public abstract class AbstractClass {public final void cookProcess() {//第一步倒油this.pourOil();//第二步热油this.heatOil();//第三步倒蔬菜this.pourVegetable();//第四步倒调味料this.pourSauce();//第五步翻炒this.fry();}public void pourOil() {System.out.println(倒油);}//第二步热油是一样的所以直接实现public void heatOil() {System.out.println(热油);}//第三步倒蔬菜是不一样的一个下包菜一个是下菜心public abstract void pourVegetable();//第四步倒调味料是不一样public abstract void pourSauce();//第五步翻炒是一样的所以直接实现public void fry(){System.out.println(炒啊炒啊炒到熟啊);} }public class ConcreteClass_BaoCai extends AbstractClass {Overridepublic void pourVegetable() {System.out.println(下锅的蔬菜是包菜);}Overridepublic void pourSauce() {System.out.println(下锅的酱料是辣椒);} }public class ConcreteClass_CaiXin extends AbstractClass {Overridepublic void pourVegetable() {System.out.println(下锅的蔬菜是菜心);}Overridepublic void pourSauce() {System.out.println(下锅的酱料是蒜蓉);} }public class Client {public static void main(String[] args) {//炒手撕包菜ConcreteClass_BaoCai baoCai new ConcreteClass_BaoCai();baoCai.cookProcess();//炒蒜蓉菜心ConcreteClass_CaiXin caiXin new ConcreteClass_CaiXin();caiXin.cookProcess();} } 注意为防止恶意操作一般模板方法都加上 final 关键词。 6.1.3 优缺点 优点 提高代码复用性 将相同部分的代码放在抽象的父类中而将不同的代码放入不同的子类中。 实现了反向控制 通过一个父类调用其子类的操作通过对子类的具体实现扩展不同的行为实现了反向控制 并符合“开闭原则”。 缺点 对每个不同的实现都需要定义一个子类这会导致类的个数增加系统更加庞大设计也更加抽象。父类中的抽象方法由子类实现子类执行的结果会影响父类的结果这导致一种反向的控制结构它提高了代码阅读的难度。 6.1.4 适用场景 算法的整体步骤很固定但其中个别部分易变时这时候可以使用模板方法模式将容易变的部分抽象出来供子类实现。需要通过子类来决定父类算法中某个步骤是否执行实现子类对父类的反向控制。 6.1.5 JDK源码解析 InputStream类就使用了模板方法模式。在InputStream类中定义了多个 read() 方法如下 public abstract class InputStream implements Closeable {//抽象方法要求子类必须重写public abstract int read() throws IOException;public int read(byte b[]) throws IOException {return read(b, 0, b.length);}public int read(byte b[], int off, int len) throws IOException {if (b null) {throw new NullPointerException();} else if (off 0 || len 0 || len b.length - off) {throw new IndexOutOfBoundsException();} else if (len 0) {return 0;}int c read(); //调用了无参的read方法该方法是每次读取一个字节数据if (c -1) {return -1;}b[off] (byte)c;int i 1;try {for (; i len ; i) {c read();if (c -1) {break;}b[off i] (byte)c;}} catch (IOException ee) {}return i;} } 从上面代码可以看到无参的 read() 方法是抽象方法要求子类必须实现。而 read(byte b[]) 方法调用了 read(byte b[], int off, int len) 方法所以在此处重点看的方法是带三个参数的方法。 在该方法中第18行、27行可以看到调用了无参的抽象的 read() 方法。 总结如下 在InputStream父类中已经定义好了读取一个字节数组数据的方法是每次读取一个字节并将其存储到数组的第一个索引位置读取len个字节数据。具体如何读取一个字节数据呢由子类实现。 6.2 策略模式 6.2.1 概述 先看下面的图片我们去旅游选择出行模式有很多种可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。 ![](file://D:\work\资料-ja va设计模式图解框架源码分析实战\Java设计模式资料day04\笔记\img\image-20200210143039168.png?msec1680705231206) 作为一个程序猿开发需要选择一款开发工具当然可以进行代码开发的工具有很多可以选择Idea进行开发也可以使用eclipse进行开发也可以使用其他的一些开发工具。 ![](file://D:\work\资料-ja va设计模式图解框架源码分析实战\Java设计模式资料day04\笔记\img\image-20200210144457478.png?msec1680705231205) 定义 ​ 该模式定义了一系列算法并将每个算法封装起来使它们可以相互替换且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式它通过对算法进行封装把使用算法的责任和算法的实现分割开来并委派给不同的对象对这些算法进行管理。 6.2.2 结构 策略模式的主要角色如下 抽象策略Strategy类这是一个抽象角色通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。具体策略Concrete Strategy类实现了抽象策略定义的接口提供具体的算法实现或行为。环境Context类持有一个策略类的引用最终给客户端调用。 6.2.3 案例实现 【例】促销活动 一家百货公司在定年度的促销活动。针对不同的节日春节、中秋节、圣诞节推出不同的促销活动由促销员将促销活动展示给客户。类图如下 ![](file://D:\work\资料-ja va设计模式图解框架源码分析实战\Java设计模式资料day04\笔记\img\策略模式.png?msec1680705231184) 代码如下 定义百货公司所有促销活动的共同接口 public interface Strategy {void show(); } 定义具体策略角色Concrete Strategy每个节日具体的促销活动 //为春节准备的促销活动A public class StrategyA implements Strategy {public void show() {System.out.println(买一送一);} }//为中秋准备的促销活动B public class StrategyB implements Strategy {public void show() {System.out.println(满200元减50元);} }//为圣诞准备的促销活动C public class StrategyC implements Strategy {public void show() {System.out.println(满1000元加一元换购任意200元以下商品);} } 定义环境角色Context用于连接上下文即把促销活动推销给客户这里可以理解为销售员 public class SalesMan { //持有抽象策略角色的引用 private Strategy strategy; public SalesMan(Strategy strategy) { this.strategy strategy; } //向客户展示促销活动 public void salesManShow(){ strategy.show(); } } 6.2.4 优缺点 1优点 策略类之间可以自由切换 由于策略类都实现同一个接口所以使它们之间可以自由切换。 易于扩展 增加一个新的策略只需要添加一个具体的策略类即可基本不需要改变原有的代码符合“开闭原则“ 避免使用多重条件选择语句if else充分体现面向对象设计思想。 2缺点 客户端必须知道所有的策略类并自行决定使用哪一个策略类。策略模式将造成产生很多策略类可以通过使用享元模式在一定程度上减少对象的数量。 6.2.5 使用场景 一个系统需要动态地在几种算法中选择一种时可将每个算法封装到策略类中。一个类定义了多种行为并且这些行为在这个类的操作中以多个条件语句的形式出现可将每个条件分支移入它们各自的策略类中以代替这些条件语句。系统中各算法彼此完全独立且要求对客户隐藏具体算法的实现细节时。系统要求使用算法的客户不应该知道其操作的数据时可使用策略模式来隐藏与算法相关的数据结构。多个类只区别在表现行为不同可以使用策略模式在运行时动态选择具体要执行的行为。 6.2.6 JDK源码解析 Comparator 中的策略模式。在Arrays类中有一个 sort() 方法如下 public class Arrays{public static T void sort(T[] a, Comparator? super T c) {if (c null) {sort(a);} else {if (LegacyMergeSort.userRequested)legacyMergeSort(a, c);elseTimSort.sort(a, 0, a.length, c, null, 0, 0);}} } Arrays就是一个环境角色类这个sort方法可以传一个新策略让Arrays根据这个策略来进行排序。就比如下面的测试类。 public class demo {public static void main(String[] args) {Integer[] data {12, 2, 3, 2, 4, 5, 1};// 实现降序排序Arrays.sort(data, new ComparatorInteger() {public int compare(Integer o1, Integer o2) {return o2 - o1;}});System.out.println(Arrays.toString(data)); //[12, 5, 4, 3, 2, 2, 1]} } 这里我们在调用Arrays的sort方法时第二个参数传递的是Comparator接口的子实现类对象。所以Comparator充当的是抽象策略角色而具体的子实现类充当的是具体策略角色。环境角色类Arrays应该持有抽象策略的引用来调用。那么Arrays类的sort方法到底有没有使用Comparator子实现类中的 compare() 方法吗让我们继续查看TimSort类的 sort() 方法代码如下 class TimSortT {static T void sort(T[] a, int lo, int hi, Comparator? super T c,T[] work, int workBase, int workLen) {assert c ! null a ! null lo 0 lo hi hi a.length;int nRemaining hi - lo;if (nRemaining 2)return; // Arrays of size 0 and 1 are always sorted// If array is small, do a mini-TimSort with no mergesif (nRemaining MIN_MERGE) {int initRunLen countRunAndMakeAscending(a, lo, hi, c);binarySort(a, lo, hi, lo initRunLen, c);return;}...} private static T int countRunAndMakeAscending(T[] a, int lo, int hi,Comparator? super T c) {assert lo hi;int runHi lo 1;if (runHi hi)return 1;// Find end of run, and reverse range if descendingif (c.compare(a[runHi], a[lo]) 0) { // Descendingwhile (runHi hi c.compare(a[runHi], a[runHi - 1]) 0)runHi;reverseRange(a, lo, runHi);} else { // Ascendingwhile (runHi hi c.compare(a[runHi], a[runHi - 1]) 0)runHi;}return runHi - lo;} } 上面的代码中最终会跑到 countRunAndMakeAscending() 这个方法中。我们可以看见只用了compare方法所以在调用Arrays.sort方法只传具体compare重写方法的类对象就行这也是Comparator接口中必须要子类实现的一个方法。 6.3 命令模式 6.3.1 概述 日常生活中我们出去吃饭都会遇到下面的场景。 ![](file://D:\work\资料-ja va设计模式图解框架源码分析实战\Java设计模式资料day04\笔记\img\image-20200211130313251.png?msec1680705231234) 定义 将一个请求封装为一个对象使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通这样方便将命令对象进行存储、传递、调用、增加与管理。 6.3.2 结构 命令模式包含以下主要角色 抽象命令类Command角色 定义命令的接口声明执行的方法。具体命令Concrete Command角色具体的命令实现命令接口通常会持有接收者并调用接收者的功能来完成命令要执行的操作。实现者/接收者Receiver角色 接收者真正执行命令的对象。任何类都可能成为一个接收者只要它能够实现命令要求实现的相应功能。调用者/请求者Invoker角色 要求命令对象执行请求通常会持有命令对象可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方也就是说相当于使用命令对象的入口。 6.3.3 案例实现 将上面的案例用代码实现那我们就需要分析命令模式的角色在该案例中由谁来充当。 服务员 就是调用者角色由她来发起命令。 资深大厨 就是接收者角色真正命令执行的对象。 订单 命令中包含订单。 类图如下 ![](file://D:\work\资料-ja va设计模式图解框架源码分析实战\Java设计模式资料day04\笔记\img\命令模式.png?msec1680705231184) 代码如下 public interface Command {void execute();//只需要定义一个统一的执行方法 }public class OrderCommand implements Command {//持有接受者对象private SeniorChef receiver;private Order order;public OrderCommand(SeniorChef receiver, Order order){this.receiver receiver;this.order order;}public void execute() {System.out.println(order.getDiningTable() 桌的订单);SetString keys order.getFoodDic().keySet();for (String key : keys) {receiver.makeFood(order.getFoodDic().get(key),key);}try {Thread.sleep(100);//停顿一下 模拟做饭的过程} catch (InterruptedException e) {e.printStackTrace();}System.out.println(order.getDiningTable() 桌的饭弄好了);} }public class Order {// 餐桌号码private int diningTable;// 用来存储餐名并记录份数private MapString, Integer foodDic new HashMapString, Integer();public int getDiningTable() {return diningTable;}public void setDiningTable(int diningTable) {this.diningTable diningTable;}public MapString, Integer getFoodDic() {return foodDic;}public void setFoodDic(String name, int num) {foodDic.put(name,num);} }// 资深大厨类 是命令的Receiver public class SeniorChef {public void makeFood(int num,String foodName) {System.out.println(num 份 foodName);} }public class Waitor {private ArrayListCommand commands;//可以持有很多的命令对象public Waitor() {commands new ArrayList();}public void setCommand(Command cmd){commands.add(cmd);}// 发出命令 喊 订单来了厨师开始执行public void orderUp() {System.out.println(美女服务员叮咚大厨新订单来了.......);for (int i 0; i commands.size(); i) {Command cmd commands.get(i);if (cmd ! null) {cmd.execute();}}} }public class Client {public static void main(String[] args) {//创建2个orderOrder order1 new Order();order1.setDiningTable(1);order1.getFoodDic().put(西红柿鸡蛋面,1);order1.getFoodDic().put(小杯可乐,2);Order order2 new Order();order2.setDiningTable(3);order2.getFoodDic().put(尖椒肉丝盖饭,1);order2.getFoodDic().put(小杯雪碧,1);//创建接收者SeniorChef receivernew SeniorChef();//将订单和接收者封装成命令对象OrderCommand cmd1 new OrderCommand(receiver, order1);OrderCommand cmd2 new OrderCommand(receiver, order2);//创建调用者 waitorWaitor invoker new Waitor();invoker.setCommand(cmd1);invoker.setCommand(cmd2);//将订单带到柜台 并向厨师喊 订单来了invoker.orderUp();} } 6.3.4 优缺点 1优点 降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦。增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类它满足“开闭原则”对扩展比较灵活。可以实现宏命令。命令模式可以与组合模式结合将多个命令装配成一个组合命令即宏命令。方便实现 Undo 和 Redo 操作。命令模式可以与后面介绍的备忘录模式结合实现命令的撤销与恢复。 2缺点 使用命令模式可能会导致某些系统有过多的具体命令类。系统结构更加复杂。 6.3.5 使用场景 系统需要将请求调用者和请求接收者解耦使得调用者和接收者不直接交互。系统需要在不同的时间指定请求、将请求排队和执行请求。系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。 6.3.6 JDK源码解析 Runable是一个典型命令模式Runnable担当命令的角色Thread充当的是调用者start方法就是其执行方法 //命令接口(抽象命令角色) public interface Runnable {public abstract void run(); }//调用者 public class Thread implements Runnable {private Runnable target;public synchronized void start() {if (threadStatus ! 0)throw new IllegalThreadStateException();group.add(this);boolean started false;try {start0();started true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {}}}private native void start0(); } 会调用一个native方法start0(),调用系统方法开启一个线程。而接收者是对程序员开放的可以自己定义接收者。 /*** jdk Runnable 命令模式* TurnOffThread 属于具体*/ public class TurnOffThread implements Runnable{private Receiver receiver;public TurnOffThread(Receiver receiver) {this.receiver receiver;}public void run() {receiver.turnOFF();} } /*** 测试类*/ public class Demo {public static void main(String[] args) {Receiver receiver new Receiver();TurnOffThread turnOffThread new TurnOffThread(receiver);Thread thread new Thread(turnOffThread);thread.start();} } 6.4 责任链模式 6.4.1 概述 在现实生活中常常会出现这样的事例一个请求有多个对象可以处理但每个对象的处理条件或权限不同。例如公司员工请假可批假的领导有部门负责人、副总经理、总经理等但每个领导能批准的天数不同员工必须根据自己要请假的天数去找不同的领导签名也就是说员工必须记住每个领导的姓名、电话和地址等信息这增加了难度。这样的例子还有很多如找领导出差报销、生活中的“击鼓传花”游戏等。 定义 又名职责链模式为了避免请求发送者与多个请求处理者耦合在一起将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链当有请求发生时可将请求沿着这条链传递直到有对象处理它为止。 6.4.2 结构 职责链模式主要包含以下角色: 抽象处理者Handler角色定义一个处理请求的接口包含抽象处理方法和一个后继连接。具体处理者Concrete Handler角色实现抽象处理者的处理方法判断能否处理本次请求如果可以处理请求则处理否则将该请求转给它的后继者。客户类Client角色创建处理链并向链头的具体处理者对象提交请求它不关心处理细节和请求的传递过程。 6.4.3 案例实现 现需要开发一个请假流程控制系统。请假一天以下的假只需要小组长同意即可请假1天到3天的假还需要部门经理同意请求3天到7天还需要总经理同意才行。 类图如下 ![](file://D:\work\资料-ja va设计模式图解框架源码分析实战\Java设计模式资料day04\笔记\img\责任链模式.png?msec1680705231205) 代码如下 //请假条 public class LeaveRequest {private String name;//姓名private int num;//请假天数private String content;//请假内容public LeaveRequest(String name, int num, String content) {this.name name;this.num num;this.content content;}public String getName() {return name;}public int getNum() {return num;}public String getContent() {return content;} }//处理者抽象类 public abstract class Handler {protected final static int NUM_ONE 1;protected final static int NUM_THREE 3;protected final static int NUM_SEVEN 7;//该领导处理的请假天数区间private int numStart;private int numEnd;//领导上面还有领导private Handler nextHandler;//设置请假天数范围 上不封顶public Handler(int numStart) {this.numStart numStart;}//设置请假天数范围public Handler(int numStart, int numEnd) {this.numStart numStart;this.numEnd numEnd;}//设置上级领导public void setNextHandler(Handler nextHandler){this.nextHandler nextHandler;}//提交请假条public final void submit(LeaveRequest leave){if(0 this.numStart){return;}//如果请假天数达到该领导者的处理要求if(leave.getNum() this.numStart){this.handleLeave(leave);//如果还有上级 并且请假天数超过了当前领导的处理范围if(null ! this.nextHandler leave.getNum() numEnd){this.nextHandler.submit(leave);//继续提交} else {System.out.println(流程结束);}}}//各级领导处理请假条方法protected abstract void handleLeave(LeaveRequest leave); }//小组长 public class GroupLeader extends Handler {public GroupLeader() {//小组长处理1-3天的请假super(Handler.NUM_ONE, Handler.NUM_THREE);}Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() 请假 leave.getNum() 天, leave.getContent() 。);System.out.println(小组长审批同意。);} }//部门经理 public class Manager extends Handler {public Manager() {//部门经理处理3-7天的请假super(Handler.NUM_THREE, Handler.NUM_SEVEN);}Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() 请假 leave.getNum() 天, leave.getContent() 。);System.out.println(部门经理审批同意。);} }//总经理 public class GeneralManager extends Handler {public GeneralManager() {//部门经理处理7天以上的请假super(Handler.NUM_SEVEN);}Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() 请假 leave.getNum() 天, leave.getContent() 。);System.out.println(总经理审批同意。);} }//测试类 public class Client {public static void main(String[] args) {//请假条来一张LeaveRequest leave new LeaveRequest(小花,5,身体不适);//各位领导GroupLeader groupLeader new GroupLeader();Manager manager new Manager();GeneralManager generalManager new GeneralManager();groupLeader.setNextHandler(manager);//小组长的领导是部门经理manager.setNextHandler(generalManager);//部门经理的领导是总经理//之所以在这里设置上级领导是因为可以根据实际需求来更改设置如果实战中上级领导人都是固定的则可以移到领导实现类中。//提交申请groupLeader.submit(leave);} } 6.4.4 优缺点 1优点 降低了对象之间的耦合度 该模式降低了请求发送者和接收者的耦合度。 增强了系统的可扩展性 可以根据需要增加新的请求处理类满足开闭原则。 增强了给对象指派职责的灵活性 当工作流程发生变化可以动态地改变链内的成员或者修改它们的次序也可动态地新增或者删除责任。 责任链简化了对象之间的连接 一个对象只需保持一个指向其后继者的引用不需保持其他所有处理者的引用这避免了使用众多的 if 或者 if···else 语句。 责任分担 每个类只需要处理自己该处理的工作不能处理的传递给下一个对象完成明确各类的责任范围符合类的单一职责原则。 2缺点 不能保证每个请求一定被处理。由于一个请求没有明确的接收者所以不能保证它一定会被处理该请求可能一直传到链的末端都得不到处理。对比较长的职责链请求的处理可能涉及多个处理对象系统性能将受到一定影响。职责链建立的合理性要靠客户端来保证增加了客户端的复杂性可能会由于职责链的错误设置而导致系统出错如可能会造成循环调用。 6.4.5 源码解析 在javaWeb应用开发中FilterChain是职责链过滤器模式的典型应用以下是Filter的模拟实现分析: 模拟web请求Request以及web响应Response public interface Request{}public interface Response{} 模拟web过滤器Filter public interface Filter {public void doFilter(Request req,Response res,FilterChain c);} 模拟实现具体过滤器 public class FirstFilter implements Filter {Overridepublic void doFilter(Request request, Response response, FilterChain chain) {System.out.println(过滤器1 前置处理);// 先执行所有request再倒序执行所有responsechain.doFilter(request, response);System.out.println(过滤器1 后置处理);} }public class SecondFilter implements Filter {Overridepublic void doFilter(Request request, Response response, FilterChain chain) {System.out.println(过滤器2 前置处理);// 先执行所有request再倒序执行所有responsechain.doFilter(request, response);System.out.println(过滤器2 后置处理);} } 模拟实现过滤器链FilterChain public class FilterChain {private ListFilter filters new ArrayListFilter();private int index 0;// 链式调用public FilterChain addFilter(Filter filter) {this.filters.add(filter);return this;}public void doFilter(Request request, Response response) {if (index filters.size()) {return;}Filter filter filters.get(index);index;filter.doFilter(request, response, this);} } 测试类 public class Client {public static void main(String[] args) {Request req null;Response res null ;FilterChain filterChain new FilterChain();filterChain.addFilter(new FirstFilter()).addFilter(new SecondFilter());filterChain.doFilter(req,res);} }
http://www.dnsts.com.cn/news/59408.html

相关文章:

  • 微信网页上的网站怎么做无锡梦燕服饰网站谁做的
  • 桂林做网站的公司哪家最好ui网页设计教程
  • 理财平台网站建设广州流感最新情况
  • wap网站建设服务工程公司取名字大全参考
  • 网站建设集团西安谁家的集团门户网站建设比较好
  • 制作一个公司网站多少wordpress 分页
  • 网站开发实用技术电子版phpcms网站模版
  • 怎么免费做文学网站自建网站做外贸谷歌推广
  • 微信网站开发模板wordpress 做的人多吗?
  • 电器网站建设目的网站关键词设几个
  • 潍坊市房屋和城乡建设局网站wordpress添加广告插件吗
  • 网站开发实现的环境网站开发的图片要求
  • 网站 域名到期学校网站建设总结报告
  • 网站开发公司加盟网络科技公司 网站建设
  • 网络运营和网站运营本溪网站设计
  • 苏州网站建设都找全网天下广阳区建设局网站
  • 山西 旅游 英文 网站建设安阳区号邮编
  • 网页休闲游戏网站采购软件管理系统
  • 小型生鲜超市店面设计企业网站seo运营
  • 房产中介网站开发游戏网站上做银商为网站人员
  • 济南网站建设appwordpress阿里百秀4.1
  • 韩国美食做视频网站有哪些wordpress如何评论
  • 可以做围棋题的网站潜江资讯网房屋出租
  • 网站接单做项目价格网站
  • 怎样建设网站php网站广告管理系统
  • 上海高端网站定制网站建设 概念股
  • 长沙哪家网站公司新浪网网站的建设费用预算
  • 网站开发的分工手机版网站如何建设
  • 旅游网站网页设计方案做效果图网站
  • 网站 信用卡支付接口加盟装修公司哪家好