zoukankan      html  css  js  c++  java
  • 设计模式分享一

    [在此处输入文章标题]

    java设计模式分享一:

    交流人: 毛平

    一:设计模式的概念:设计模式是一套反复被使用,经过分类编目的优秀代码设计经验的总结。使用设计模式是为了重用代码,使代码更易理解并保证代码的有效性。使代码编制真正的工程化。

    可复用面向对象软件系统一般分为两大类:应用程序工具箱和框架。其中java的基础类库属于工具箱,而框架是构成特定软件可复用设计的一组相互协作的类。框架通常定义了应用体系的整体结构类和对象关系设计参数。

    java设计模式贯彻的原理是:面向接口编程,而不是面向实现。其目标原则是:降低耦合,增加灵活性。

    二:设计模式的大致了解:

    设计模式的分类:常用设计模式有23种,可以分为三类。创建型结构型行为型

    l 创建型:创建型模式是用来创建对象的模式,抽象了实例化的过程。创建型有两个主要的功能。

    1. 将系统所使用的具体类的信息封装起来。

    2. 隐藏类的实例是如何被创建和组织起来的,外界对这些对象只知道他们共同的接口,而不清楚他们具体的实现细节。

    常见的创建型模式有5种。单例模式工厂模式抽象工厂模式建造者模式原型模式

    l 结构型:结构型模式讨论的是类和对象的结构,它采用了继承机制来组合接口或者实现。通过组合一些对象来实现新的功能(对象结构型模式)。结构型模式在某些方面很大的类似,但侧重点不同。

    结构型模式有以下几种。

    3. 代理模式(proxy):为其它对象提供一种代理以控制对该对象的访问。

    4. 装饰模式:动态的给添加一些额外的职责。就增加功能而言,装饰模式比生成子类还要灵活。

    5. 适配器模式:将一个累的接口变换成客户端所期待的另一个接口。从而是原本接口不匹配而不能在一起工作的两个类在一起工作。

    6. 组合模式:也叫合成模式。讲对象组成书香模式以表示“部分-整体”的层次结构。使得用户对单个对象和组合对象的使用具有一致性。

    7. 桥梁模式:将抽象和实现解耦,使两者可以独立变化。

    8. 外观模式:要求一个子系统的外部和内部的通信必须通过一个统一的对象进行。外观模式提供了一个高层次的接口。使得子系统更易使用。

    9. 享元模式:是池技术的重要实现方式。使用共享对象可以有限的支持大量的细粒度的对象。

    l 行为型:关注对象的行为,用来解决对象之间的联系问题。

    10. 模板方法模式:定义了一个操作中的算法框架,从而将一些步骤延迟到子类中,使得子类可以不改变算法结构而重新定义算法的某些特定步骤。

    11. 命令模式:是一个高内聚的模式,将一个请求封装成一个对象,从而使不同的请求把客户端参数化,对请求排队或者记录请求的日志,可以提供命令撤销和恢复的功能。

    12. 责任链模式:使多个对象都有机会处理请求,从而避免了发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有对象处理为止。

    13. 策略模式:定义一组算法,将每个算法封装起来,并且他们之间可以相互切换。

    14. 迭代式模式:提供了访问某个容器中的各个元素,而不需要暴露该对象之中的内部细节。

    15. 中介者模式:用一个中介对象封装一系列对象交互。中介找使对象之间不需要显示的相互作用,从而是耦合松散,可以独立的改变他们之间的交互。

    16. 观察者模式:也叫发布订阅模式,定义了一种一对多的依赖关系。使得每当一个对象状态改变,则左右依赖他的对象都会得到通知并被自动更新。

    17. 备忘录模式:在不破坏封装性的前提下,扑捉一个对象的内部状态。并在该对象之外保存这个状态。

    18. 访问者模式(visitor: 封装一个对于某种结构中各元素的操作,他可以在不改变数据结构的前提下作用于这些元素的新操作。

    19. 状态模式:当一个对象内部状态改变允许我们改变其行为,这个对象看起来像改变了其类型,状态模式的核心是封装,状态的变更引起更多行为的变更。

    20. 解析器模式:给定一种语言,定义他的文法的一种表示,并定义了一个解析器。解析器使用该文法表示来解析语言中的句子。

    三:设计模式的实例分享。选取其中的4个设计模式,具体分享。

    l 单例模式

    需要管理全局信息的时候,通常使用单例模式。比如,1.多次查询信息结果一致,多次查询就变得浪费。2.当前在线人数,从运行程序中可以获取。数字实时变化,没必要每次都去获取。可以去单例去记录,直接从单例属性汇总获取。

    21. 核心知识点如下:

    (1) 将采用单例设计模式的类的构造方法私有化(采用private修饰)。

    (2) 在其内部产生该类的实例化对象,并将其封装成private static类型。

    (3) 定义一个静态方法返回该类的实例。

    /** * 方法一 * 单例模式的实现:饿汉式,线程安全 但效率比较低 */ public class SingletonTest {

    // 定义一个私有的构造方法 private SingletonTest() { }

    // 将自身的实例对象设置为一个属性,并加上Static和final修饰符 private static final SingletonTest instance = new SingletonTest();

    // 静态方法返回该类的实例 public static SingletonTest getInstancei() { return instance; } }

    方法一就是传说的中的饿汉模式

    优点是:写起来比较简单,而且不存在多线程同步问题,避免了synchronized所造成的性能问题;

    缺点是:当类SingletonTest被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后,这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。

    /** *方法二 * 单例模式的实现:饱汉式,非线程安全 * */ public class SingletonTest {

    // 定义私有构造方法(防止通过 new SingletonTest()去实例化) private SingletonTest() { }

    // 定义一个SingletonTest类型的变量(不初始化,注意这里没有使用final关键字) private static SingletonTest instance;

    // 定义一个静态的方法(调用时再初始化SingletonTest,但是多线程访问时,可能造成重复初始化问题) public static SingletonTest getInstance() { if (instance == null) instance = new SingletonTest(); return instance; } }

    方法二就是传说的中的饱汉模式

    优点是:写起来比较简单,当类SingletonTest被加载的时候,静态变量static的instance未被创建并分配内存空间,当getInstance方法第一次被调用时,初始化instance变量,并分配内存,因此在某些特定条件下会节约了内存;

    缺点是:并发环境下很可能出现多个SingletonTest实例。

    UML 类图

    clip_image002

    单例也是设计模式中最基础的一种,面试基本上都会碰到。在 城市观测盒子 中有使用。上代码吧:

    单例,提供全局的一份统一数据,方便程序中的任何时刻的调用:

    clip_image004

    只所以能达到目的,是因为获取单例对象的方式只有一种,GlobalInstance.getInstance() 。

    总结:单例模式是设计模式中最简单最基础的一种模式,在特定的场景下需要一个程序中运行一份数据的时候使用。实现的手段是 构造方法私有化,向外部提供统一的一个获取入口。GlobalInstance.getInstance() ,每次获取的是同一个对象。

    l 工厂模式

    工厂模式的用意是定义一个创建产品对象的工厂接口。将实际的创建共组推迟到子类中。

    UML类图

    clip_image006

    工厂方法1.png

    工厂模式针对的是一个产品登记的结构。

    工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。

    工厂模式在使用中特别普遍,荣成接口对接 中有使用到。直接上代码:

    工厂接口:

    clip_image008

    工厂实现:

    clip_image010

    产品接口-接口或者抽象类:

    clip_image012

    产品实现A:

    clip_image014

    产品实现B:

    clip_image016

    工厂模式最直观的有点就在于代码更紧凑,易读性强。新建类有一个工厂一样为运行代码提供需要的实现类。个人以为,工厂模式有更深刻的意义在于,程序运行中更多依赖接口而不是依赖实体类,更多依赖抽象而非具体。这个原则也是开发的原则。比如,业务中 一个人工作三个小时,休息半个小时,和美女游戏30分钟,使用工厂模式,在运行过程中 根据实际情况 ,工厂创建一个张三或者李四来依次做这些事情。如果代码直接写死意味着操作的实体类改变,所有的代码都要修改。如果有新的实体类,只需要在工厂类产生对应的实体类即可。不需要修改原有的实体类代码。对扩展开放,对修改关闭。

    工厂模式和spring框架的IOC思想契合度很高在运行的过程中再去决定谁来执行,控制被翻转。执行依赖与注入的实现类。

    l 适配器模式

    场景介绍:

    我们出国时,通常会带上电子产品的充电设备,可是,不同国家的插线标准准不一样,美标,俄表,我们的国标等等。如果标准不一致,我们是不能直接使用当地的插线板,那么,我们需要买插线转换器,其中,插线转换器的功能就是插到当地的产线板上,然后提供我们能使用的插孔,做一个格式转换。这就是适配器的功能。

    软件行业中,在旧项目升级的过程中,我们有可能需要一个新的功能接口,和以往的功能接口相似度很高。如果我们重新开发所有功能,意味着代码量会很高,这个时候,我们就可以使用适配器模式来开发新功能,在保证不修改原有接口的前提下,开发新的接口,和充电线的转换器一样,后台使用原有的功能,给外部提供新的接口数据。最大限度的使用了原有的代码。

    其中,适配器模式有两种方式,类适配器和对象适配器。

    类转换器

    火鸡转鸭子:商店生产鸭子

    商店原本具备生产火鸡的功能。现在需要生产鸭子。 生产火鸡的功能如下:

    火鸡接口如下:

    clip_image018

    火鸡实现

    clip_image020

    如果按照传统的方式去开发鸭子功能,结果如下

    鸭子接口如下:

    clip_image022

    鸭子实现

    clip_image024

    如此,我们开发一套完整的新需求代码。

    如果 使用适配器模式开开发的话,如下:对象适配器:

    clip_image026

    类是适配器

    clip_image028

    两种适配器都实现了这个功能。

    总结:在旧产品升级的时候,新的功能基于已经存在的接口或者实体类。或者新的功能和旧的功能相似度很高,只需要在少量的地方变化,就可以基于适配器模式依托旧的功能开发新的接口,节省开发工作量。

    暂时没有实际代码运行使用场景。

    l 命令模式

    场景介绍:

    1. 命令的发送者和命令执行者有不同的生命周期。命令发送了并不是立即执行。2. 命令需要进行各种管理逻辑。3. 需要支持撤消重做操作。

    l 三个内容

    22. 命令模式执行

    23. 宏

    24. undo

    l 基本内容

    命令模式中一般会有四中角色

    Command:定义命令的统一接口

    ConcreteCommand:Command接口的实现者,用来执行具体的命令,某些情况下可以直接用来充当Receiver。

    Receiver:命令的实际执行者

    Invoker:命令的调用器,是命令模式中最重要的角色。这个角色用来对各个命令进行控制。

    示例一:

    Command:

    clip_image030

    ConcreteCommand:

    命令实现类A:

    clip_image032

    命令接口实现类B:

    clip_image034

    Receiver:命令的实际执行者

    clip_image036

    Invoker:命令的调用器:

    clip_image038

    总结:扩展性比较好,新添加命令不会影响其它已经存在代码的运行。

    示例2:与传统处理相互比较,学习命令模式

    家电设备遥控器,有5排按钮,分别为开关。用来控制家里电灯,音响等。

    clip_image040

    果按照传统开发结果:

    想要控制的业务接口:

    clip_image042

    控制的对象 -灯:

    clip_image044

    控制的对象 -音响

    clip_image046

    传统控制类实现代码如下:

    clip_image048

    传统代码实现测试类:

    clip_image050

    传统代码实现总结:功能基本实现,1.多个目标功能和实现载体强相关(音响的相关功能都在音响类中,修改音响任何一个功能不可避免的可能对其它功能有影响),2.代码编写好之后,方法和按钮之间的关系是强关联。3.不能实现undo功能

    命令模式之 基础 功能:

    命令接口:

    clip_image052

    功能命令实现:(将功能做很细小的拆分)

    开灯命令:

    clip_image054

    关灯命令:

    clip_image056

    开音响:

    clip_image058

    关音响:

    clip_image060

    调大音响:

    clip_image062

    调小音响:

    clip_image064

    无操作命令:

    clip_image066

    命令模式实现遥控器:

    clip_image068

    命令模式测试类:

    clip_image070

    总结:单纯从功能上实现角度来比较,1.功能命令化,最小限度的和实现载体关联。同一实现载体之间的功能没有任何的联系。2.命令和按钮之间可以动态绑定(手机遥控器app可以动态的绑定电视机)。3.可以实现undo。4.核心的优势:最大限度的做到了对扩展开放,对修改关闭(扩展功能不基于修改代码)。

    命令模式之 宏命令 功能。

    宏命令实现类:

    clip_image072

    可以将多个命令绑定在封装为一个命令执行。接口对接中有关于宏命令的处理。

    接口对接有ws通用接口处理和https接口对接。两种接口对接处理都实现命令接口。宏处理也实现命令接口。宏命令中有接口数组参数用于封装单个命令,实现命令执行遍历命令数据实现单个命令。

    https接口处理:

    clip_image074

    WS接口处理:

    clip_image076

    宏处理:

    clip_image078

    实际的代码可以看出,命令模式不但让功能清晰,可以自我包含,宏命令可以继续封装宏命令。

    命令模式之 undo 功能。

    撤销回退功能,基本上都是基于命令模式完成。

    1. 单个命令的undo

    取决于实际业务有与之相对的执行功能。比如灯的开关,音量的调大调小。

    clip_image080

    2.宏命令的undo,逆序执行撤销。

    clip_image082

    3.控制类的undo(最常见-已经有多个操作后,希望回退)

    clip_image084

    主要实现方式,执行命令进行压栈且执行命令,undo的时候出栈且执行undo(撤销).利用堆栈的后进先出的特性。

    总结:命令模式有特殊的使用场景,会让编码灵活性更高。设计模式让开发代码的理解深刻。同时,设计模式中还有一些特别有意思的设计模式,比较喜欢且很重要的模式有:代理模式,访问者模式,观察者模式,状态模式。

    简单了解:

    代理模式:业务实现类作为代理类属性,代理类也和业务实现类继承同样接口,代理类对业务接口的实现其实是实现类的实现。不过可以在实现的前后添加自己的方法。其中spring的AOP其中一种方式就是通过动态代理的方式在实现面向切面功能。在制定位置处添加自己想添加的代码。

    访问者模式:访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。

    观察者模式:类似订阅一样,检测一个数据状态,如果状态转变,可以通知所有的观察者。

    状态模式:类似游戏NPC添加新的功能,隐藏,战斗,逃走,飞行等等,传统模式开发需要提前知道有哪些功能,需要完成各种功能的开发。状态模式只需要添加新的状态以及实现该状态下的新功能。可以轻松的升级NPC的功能。

    设计模式因为设计精巧所有有意思,理解设计思想并运用在工作中让工作更有趣。

    谢谢大家!

    2017年11月9日 20:22:05

  • 相关阅读:
    Jmeter_完成文件批量下载
    Jmeter_文件的下载
    Jmeter_针对一个账户批量上传文件
    Jmeter上传文件操作
    Jmeter_获取结果写到excel
    Jmeter_接口串联自动化测试_登录后充值获取cookie
    JS 对象(Object)和字符串(String)互转
    全国图书馆参考咨询联盟关闭文献传递功能解决办法
    Geodesic Distance:两点间的最短距离之法截弧/等角航线/测地线
    空间数据库基础理论 GIS空间数据处理分析涉及的基本概念
  • 原文地址:https://www.cnblogs.com/maopneo/p/8477355.html
Copyright © 2011-2022 走看看