-
Java设计模式精讲
2015-02-04 10:44:07您是一个初级的 coder,可以从中领会到怎么设计一段优秀的...您是一个高级程序员,可以从中全面了解到设计模式以及 Java 的边角技术的使用;您是一个顶级的系统分析师,可以从中获得共鸣,寻找到项目公共问题的解决办法 -
java设计模式精讲 Debug 方式+内存分析
2019-01-25 09:20:04java设计模式精讲 Debug 方式+内存分析, -
【设计模式】Java设计模式精讲之原型模式
2020-01-27 23:18:14简单记录 - 慕课网 Java设计模式精讲 Debug方式+内存分析 & 设计模式之禅-秦小波 & 软件秘笈-设计模式那些事-郑阿奇 文章目录1、原型模式的定义原型-定义原型-类型2、原型模式的实现原型模式的通用类图原型...简单记录 - 慕课网 Java设计模式精讲 Debug方式+内存分析 & 设计模式之禅-秦小波
文章目录
原型模式(Prototype Pattern)的简单程度仅次于单例模式和迭代器模式。正是由于简单,使用的场景才非常地多。原型模式是创建型模式,创建型模式一般用来创建一个新的对象,然后使用这个对象完成一些对象的操作,我们通过原型模式可以快速地创建一个对象而不需要提供专门的new()操作,这无疑是一种非常有效的方式,可以快速地创建一个新的对象。1、原型模式的定义
原型-定义
定义:
-
指原型实例指定创建对象的种类,并且通过拷贝(复制)这些原型创建新的对象。
-
不需要知道任何创建的细节,不调用构造函数。
Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.
原型-类型
类型:创建型模式-原型模式
原型模式的最大的特点就是克隆一个现有的对象,这个克隆的结果有两种,一种是浅复制,另一种是深复制。
比其他的简单多,那怎么用好它,这是个问题。
2、原型模式的实现
原型模式的通用类图
原型模式的通用类图
实线箭头 关联关系
三角空心实线 泛化(继承)关系
原型模式的核心是一个clone方法,通过该方法进行对象的拷贝(复制),Java提供了一个Cloneable接口来标示这个对象是可拷贝的,为什么说是“标示”呢?
翻开JDK的帮助看看Cloneable是一个方法都没有的,这个接口只是一个标记作用,在JVM中具有这个标记的对象才有可能被拷贝。
那怎么才能从“有可能被拷贝”转换为“可以被拷贝”呢?方法是覆盖clone()方法,重写clone()方法。
在clone()方法上增加了一个注解@Override,没有继承一个类为什么可以覆写呢?
在Java中所有类的老祖宗是谁?是Object类,每个类默认都是继承了这个类,所以用覆写是非常正确的——覆写了Object类中的clone方法!在Java中原型模式是如此简单的。那到底如何实现呢?
原型模式通用源码
PrototypeClass.java
/** * 原型模式通用代码 */ public class PrototypeClass implements Cloneable{ //覆写父类Object方法 @Override public PrototypeClass clone(){ PrototypeClass prototypeClass = null; try { prototypeClass = (PrototypeClass)super.clone(); } catch (CloneNotSupportedException e) { //异常处理 } return prototypeClass; } }
实现一个接口Cloneable,然后重写clone方法,就完成了原型模式!
3、原型模式的使用场合
原型模式的适用场景 适合什么场景用
- 类初始化消耗较多资源
- new产生的一个对象需要非常繁琐得过程(数据准备、访问权限等)
- 构造函数比较复杂
- 循环体中生产大量对象时
原型模式的使用场景 想用原型模式时的场景
- 资源优化场景
类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
- 性能和安全要求的场景
通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
简化创建过程
- 一个对象多个修改者的场景
一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与Java融为一体,我们可以随手拿来使用。
4、原型模式的应用
原型模式-优点
原型模式-优点
- 性能优良
原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。(原型模式性能比直接new一个对象性能高)
- 逃避构造函数的约束
这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点就是减少了约束,缺点也是减少了约束,使用需要在实际应用时考虑。
原型模式性能比直接new一个对象性能高
简化创建过程
原型-缺点
缺点
- 必须配备克隆方法
重写
- 对克隆复杂对象或克隆出的对象进行复杂改造时,容易引入风险
- 深拷贝、浅拷贝要运用得当
很多坑
原型模式的注意事项
原型模式clone方法的有一些注意事项的。
构造函数不会被执行
一个实现了Cloneable并重写了clone方法的类A,有一个无参构造或有参构造B(B是构造函数),通过new关键字产生了一个对象S,再然后通过S.clone()方式产生了一个新的对象T,那么在对象拷贝时构造函数B是不会被执行的。 即对象拷贝时不会执行构造函数的。
一小段程序来说明这个问题,如代码所示。
代码简单的可拷贝对象 Thing.java
/** * 万物 */ public class Thing implements Cloneable{ public Thing(){ System.out.println("构造函数被执行了..."); } @Override public Thing clone(){ Thing thing=null; try { thing = (Thing)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return thing; } }
然后我们再来写一个Client类,进行对象的拷贝,如代码所示。
简单的场景类 Client.java
/** * Client */ public class Client { public static void main(String[] args) { //产生一个对象 Thing thing = new Thing(); //拷贝一个对象 Thing cloneThing = thing.clone(); } }
运行结果如下所示:
构造函数被执行了... Process finished with exit code 0
这个创建对象
//产生一个对象 Thing thing = new Thing();
执行了一次构造函数
对象拷贝时构造函数确实没有被执行,这点从原理来讲也是可以讲得通的,Object类的clone方法的原理是从内存中(具体地说就是堆内存)以二进制流的方式进行拷贝,重新分配一个内存块,那构造函数没有被执行也是非常正常的了。
浅拷贝和深拷贝
在解释什么是浅拷贝和什么是深拷贝之前,先来看个例子,如代码所示。
浅拷贝
/** * 万物 */ public class Thing implements Cloneable{ //定义一个私有变量 private ArrayList<String> arrayList = new ArrayList<String>(); @Override public Thing clone(){ Thing thing=null; try { thing = (Thing)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return thing; } //设置HashMap的值 public void setValue(String value){ this.arrayList.add(value); } //取得arrayList的值 public ArrayList<String> getValue(){ return this.arrayList; } }
在Thing类中增加一个私有变量arrayList,类型为ArrayList,然后通过setValue和getValue分别进行设置和取值,我们来看场景类是如何拷贝的,
如代码清单所示。 浅拷贝测试
/** * 场景类 */ public class Client { public static void main(String[] args) { //产生一个对象 Thing thing = new Thing(); //设置一个值 thing.setValue("张三"); //拷贝一个对象 Thing cloneThing = thing.clone(); cloneThing.setValue("李四"); System.out.println(thing.getValue()); } }
猜想一下运行结果应该是什么?是仅一个“张三”吗?
运行结果如下所示:[张三,李四]
怎么会这样呢?怎么会有李四呢?是因为Java做了一个偷懒的拷贝动作,Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝。
确实是非常浅,两个对象共享了一个私有变量,你改我改大家都能改,是一种非常不安全的方式,在实际项目中使用还是比较少的(当然,这也是一种“危机”环境的一种救命方式)。
你可能会比较奇怪,为什么在Mail那个类中就可以使用String类型,而不会产生由浅拷贝带来的问题呢?内部的数组和引用对象才不拷贝,其他的原始类型比如int、long、char等都会被拷贝,但是对于String类型,Java就希望你把它认为是基本类型,它是没有clone方法的,处理机制也比较特殊,通过字符串池(stringpool)在需要的时候才在内存中创建新的字符串,读者在使用的时候就把String当做基本类使用即可。
注意 使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个原始类型或不可变对象。浅拷贝是有风险的,那怎么才能深入地拷贝呢?我们修改一下程序就可以深拷贝,如代码所示。
代码 深拷贝
/** * 万物 */ public class Thing implements Cloneable{ //定义一个私有变量 private ArrayList<String> arrayList = new ArrayList<String>(); @Override public Thing clone(){ Thing thing=null; try { thing = (Thing)super.clone(); thing.arrayList =(ArrayList<String>)this.arrayList.clone();//深拷贝 } catch (CloneNotSupportedException e) { e.printStackTrace(); } return thing; } //设置HashMap的值 public void setValue(String value){ this.arrayList.add(value); } //取得arrayList的值 public ArrayList<String> getValue(){ return this.arrayList; } }
仅仅增加了
thing.arrayList =(ArrayList<String>)this.arrayList.clone();//深拷贝
,对私有的类变量进行独立的拷贝。Client类没有任何改变,运行结果如下所示:[张三]该方法就实现了完全的拷贝,两个对象之间没有任何的瓜葛了,你修改你的,我修改我的,不相互影响,这种拷贝就叫做深拷贝。深拷贝还有一种实现方式就是通过自己写二进制流来操作对象,然后实现对象的深拷贝,有时间实现一下。
注意: 深拷贝和浅拷贝建议不要混合使用,特别是在涉及类的继承时,父类有多个引用的情况就非常复杂,建议的方案是深拷贝和浅拷贝分开实现。
clone与final两个冤家
对象的clone与对象内的final关键字是有冲突的,我们举例来说明这个问题,如代码所示。
代码 增加final关键字的拷贝
** * 万物 */ public class Thing implements Cloneable{ //定义一个私有变量 private final ArrayList<String> arrayList = new ArrayList<String>(); @Override public Thing clone(){ Thing thing=null; try { thing = (Thing)super.clone(); this.arrayList = (ArrayList<String>)this.arrayList.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return thing; } //设置HashMap的值 public void setValue(String value){ this.arrayList.add(value); } //取得arrayList的值 public ArrayList<String> getValue(){ return this.arrayList; } }
粗体部分仅仅增加了一个final关键字,然后编译器就报斜体部分错误,正常呀,final类型你还想重赋值呀!你要实现深拷贝的梦想在final关键字的威胁下破灭了,路总是有的,我们来想想怎么修改这个方法:删除掉final关键字,这是最便捷、安全、快速的方式。你要使用clone方法,在类的成员变量上就不要增加final关键字。注意 要使用clone方法,类的成员变量上不要增加final关键字。这个代码去掉final就可以运行了
原型-扩展
扩展
- 深克隆
- 浅克隆
Coding
源码解析
克隆
扩展:Java SDK中的原型模式其实,在上面的例子中,我们就已经在使用JDK中的原型设计模式了。Object类是所有类的超类,子类可以重载Object类的clone方法克隆对象,但是必须记得一定要实现Cloneable接口才行,因为只有实现该接口的对象才能被复制。Object类的原型模式如图所示。
5、设计原则
原型模式的核心是一个clone方法,通过这个方法进行对象的复制,在Java中,提供了一个Cloneable接口来标示这个对象是可复制的,为什么说是“标示”呢?查看Cloneable类源码,会发现,Cloneable接口中一个方法都没有,这个接口的作用就是一个标示,只有实现该接口的对象才有可能被复制!到这里你可能又要问了,那又如何从“有可能被复制”变为“可以被复制”呢?方法就是覆盖超类的clone()方法!
原型设计模式的原则还是在解耦上。我们在类的交互中可以不把类名塞到源文件中,那样类将耦合在一起,达不到类复用的作用。当然,必须紧密结合在一起的类是应当将类名写到一起的,以增加系统的高内聚性,而那些应该独立成组件的类,则应当被分离出来。
6、最佳实践
原型模式先产生出一个包含大量共有信息的类,然后可以拷贝出副本,修正细节信息,建立了一个完整的个性对象。原型模式也就是由一个正本可以创建多个副本的概念。可以这样理解:一个对象的产生可以不由零起步,直接从一个已经具备一定雏形的对象克隆,然后再修改为生产需要的对象。
7、总结
1.原型模式
用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
2.注意事项
(1)克隆对象时,原始对象的构造方法不被执行。
(2)浅复制:浅复制只是复制本对象的原始数据类型,如int、float、String等,对于数组和对象引用等是不会复制的。因此,浅复制是有风险的。
(3)深复制:不但对原始数据类型做复制,对于对象中的数组和对象引用也做复制的行为,从而达到将对象完全复制的效果。
3.设计原则
(1)考虑产生对象的复杂度和类复用;
(2)结合系统结构考虑使用浅复制还是深复制。
4.使用场合
(1)产生对象过程比较复杂,初始化需要许多资源时;
(2)希望框架原型和产生对象分开时;
(3)同一个对象可能会供其他调用者同时调用访问时。
原型模式(Proxy Pattern)
定义:Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype. 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式的通用类图如下图:
原型模式的核心是一个clone方法,通过该方法进行对象的拷贝,Java提供了一个Cloneable接口来标示这个对象是可拷贝的,为什么说是“标示”呢?翻开JDK的帮助看看Cloneable是一个方法都没有的,这个接口只是一个标记作用,在JVM中具有这个标记的对象才有可能被拷贝,那怎么才能从“有可能被拷贝”转换为“可以被拷贝”呢?方法是覆盖clone()方法。实现一个接口,然后重写clone方法,就完成了原型模式!
原型模式的应用
1.原型模式的优点
- 性能优良。原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好的体现其优点。
- 逃避构造函数的约束。这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的(见“原型模式的注意事项”),优点就是减少了约束,缺点也是减少了约束,双刃剑,需要大家在实际应用时考虑。
2.原型模式的使用场景
- 资源优化场景。类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
- 性能和安全要求的场景。通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
- 一个对象多个修改者的场景。一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与Java融为浑然一体,大家可以随手拿来使用。
原型模式的注意事项
- 构造函数不会被执行。
- 浅拷贝和深拷贝。Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝,确实是非常浅,两个对象共享了一个私有变量,你改我改大家都能改,是一种非常不安全的方式,在实际项目中使用还是比较少的(当然,这是也是一种“危机”环境的一种救命方式)。内部的数组和引用对象才不拷贝,其他的原始类型比如int,long,String(Java就希望你把String认为是基本类型,String是没有clone方法的)等都会被拷贝的。(注意:使用clone方法拷贝时,满足两个条件的对象才不会被拷贝:一是类的成员变量,而不是方法内的变量;二是必须是一个对象,而不是一个原始类型)
- clone与final两对冤家。对象的clone与对象内的final关键字是有冲突的。要使用clone方法,类的成员变量上不要增加final关键字。
-
-
java设计模式精讲 /Debug 方式/内存分析(包含其他缺失的16章)
2019-03-31 17:41:23java设计模式精讲 /Debug 方式/内存分析(包含其他缺失的16章) -
Java设计模式精讲之UML急速入门
2020-01-26 20:26:37简单记录 - 慕课网 - Java设计模式精讲 Debug方式+内存分析 文章目录第2章 UML急速入门2-1、UML简单入门UML定义UML特点UML 2.2分类UML类图理解泛化、实现理解依赖、关联理解聚合、组合UML时序图2-2、UML类 图讲解2-3...简单记录 - 慕课网 - Java设计模式精讲 Debug方式+内存分析
文章目录
第2章 UML急速入门
主要讲解UML基础、UML类图、UML类关系、UML时序图、UML类关系记忆技巧等,让大家急速入门UML,从而为后面设计模式的学习做好准备。
- 2-1 本章导航
- 2-2 UML类图讲解
- 2-3 UML类图讲解-自上而下
- 2-4 UML类图讲解-对比讲解联想记忆
2-1、UML简单入门
UML类图及时序图入门
定义 特点 分类
类图 时序图 记忆技巧
UML角度 理解 设计模式
UML定义
UML定义
- 统一建模语言(英文:Unified Modeling Language,缩写UML)
- 非专利的第三代建模和规约语言
UML特点
UML特点
-
UML是一种开发的方法
-
用于说明、可视化、构建和编写一个正在开发的面向对象的、软件密集系统的制品的开发方法。
制品 软件开发过程中 产物 模型 各种流程图 源代码 测试用例 等等 可视化 描述
-
UML展现了一系列最佳工程实践
这些最佳实践在对大规模,复杂系统进行建模方面,特别是在软件架构层次已经被验证有效 通过UML对系统更深理解
UML 2.2分类
UML2.2中一共定义了14种图示,分类如下:
- 结构式图形:强调的是系统式的建模
- 行为式图形:强调系统模型中触发的事件
- 交互式图形:属于行为式图形子集合,强调系统模型中资料流程。
结构式图形
- 静态图(类图、对象图、包图)
- 实现图(组件图、部署图)
- 剖面图
- 复合结构图
行为式图形
- 活动图
- 状态图
- 用例图
交互式图形
- 通信图
- 交互概述图(UML2.0)
- 时序图(UML2.0)
- 时间图(UML2.0)
UML类图
- Class Diagram:用于表示类、接口、实例等之间相互的静态关系
- 虽然名字叫类图,但类图中并不只是类 包括权限、属性、方法等等
理解泛化、实现
泛化关系 继承关系 记忆技巧
-
UML箭头方向:从子类指向父类
-
提示:可能会认为子类是以父类为基础的,箭头应从父类指向子类
从来没有这么想过
记忆技巧-箭头方向
- 定义子类时需要通过extends关键字指向父类
- 子类一定是知道父类定义的,但父类并不知道子类的定义
- 只有知道对方信息时才能指向对方
UML 所以箭头方法从子类指向父类
实线-继承 | 虚线-实现
实现关系
-
被一个类实现了 ,A类实现B接口 实现关系
-
三角空心虚线
实现关系、继承关系
实线-继承 | 虚线-实现
-
空心三角箭头:继承或实现
-
实线-继承 ,is a 关系,扩展目的,不虚,很结实的。
-
虚线-实现,虚线代表“虚”无实体。实现接口 实现接口方法
理解依赖、关联
实线 -关联 | 虚线-依赖
关联关系 实线
依赖关系
实线 -关联 | 虚线-依赖
依赖关系 虚线
-
虚线-依赖关系:临时用一下,若即若离,虚无缥缈,若有若无
调用的时候才会用一下 虚线 依赖关系
-
表示一种使用关系,一个类需要借助另一个类来实现功能
-
一般是一个类使用另一个类做为参数使用,或作为返回值 参数 返回值
关系关系 实线
- 实线-关联关系:关系稳定,实打实的关系,铁哥们。
- 表示一个类对象和另一个类对象有关联
- 通过是一个类中有另一个类对象做为属性 属性 一个成员变量
理解聚合、组合
空心菱形-聚合 | 实心菱形-组合
-
菱形就是一个盛东西的器皿(例如盘子)
-
聚合:代表空器皿里可以放很多相同的东西,聚在一起(箭头方向所指的类 个体
-
组合:代表满器皿里已经有实体结构的存在,生死与共 强关系
整体与部分 可以离聚合 不可以离组合
组合关系
鸟和翅膀 人和头 强关系 相同的生命周期 你死我也死
数字?
空心菱形 聚合关系 记忆技巧
-
整体和局部的关系,两者有着独立的生命周期,是has a的关系
-
弱关系
大雁群 has a 大雁
-
消极的词:弱 - 空 空心菱形
实心菱形 组合关系 记忆技巧
-
整体与局部的关系,和聚合的关系相比,关系更加强烈
两者有相同的生命周期,contains-a的关系 包含
-
强关系
-
积极的词:强 - 满 实心菱形
常见数字表达及含义
一个鸟 两个翅膀
UML时序图
生命线 上到下 时间的流逝
方法调用
消息
类图 时序图 用例图 重要
时序图 调用关系
2-2、UML类 图讲解
类的表示
类名 抽象类 斜体表示 接口 <>
属性 行为
public
+private
-protected
#什么都不加 or
~
是表示 default+
max-
min private#
protected横线 static 属性
横线 static 静态方法
斜体 抽象方法 有抽象方法 是抽象类 要斜体来表示一下咯所以上面那个图错了
是抽象类 有抽象方法
有抽象方法的是抽象类 抽象类要斜体来表示一下
记住这个类图
类图表示 要 准确 避免产生歧义
2-3、UML类图讲解 自上而下
大话设计模式的图 UML图
一起来学习吧
依赖关系
虚线箭头 箭头方向 指向被依赖的对象
- 表示一种使用关系,一个类需要借助另一个类来实现功能
- 一般是一个类使用另一个类做为参数使用,或作为返回值 参数 返回值
鸟是一种动物
父类 子类 鸟继承动物 箭头方向:子类指向父类-
UML箭头方向:从子类指向父类
-
提示:可能会认为子类是以父类为基础的,箭头应从父类指向子类
从来没有这么想过
记忆技巧-箭头方向
- 定义子类时需要通过extends关键字指向父类
- 子类一定是知道父类定义的,但父类并不知道子类的定义
- 只有知道对方信息时才能指向对方
UML 所以箭头方法从子类指向父类
实线-继承 | 虚线-实现
-
空心三角箭头:继承或实现
-
实线-继承 ,is a 关系,扩展目的,不虚,很结实的。
-
虚线-实现,虚线代表“虚”无实体。实现接口 实现接口方法
关联关系
关联关系 实线
- 实线-关联关系:关系稳定,实打实的关系,铁哥们。
- 表示一个类对象和另一个类对象有关联
- 通过是一个类中有另一个类对象做为属性 属性 一个成员变量
有一个类对象的属性
聚合关系
空心菱形 聚合关系 记忆技巧
-
整体和局部的关系,两者有着独立的生命周期,是has a的关系
-
弱关系
大雁群 has a 大雁
-
消极的词:弱 - 空 空心菱形
整体 大雁群 局部、部分 大雁
空心菱形 菱形指向很多大雁也就是大雁群 箭头指向大雁
实现关系 空心三角虚线 表示实现关系
空心三角虚线 大雁实现了飞翔这个接口
棒棒糖表示法 接口表示 实现关系
2-4、UML类图讲解 - 对比讲解联想记忆
依赖关系 虚线箭头 参数、返回值 使用的时候才会关注
关联关系 实线箭头 实打实的关系 ,一般用了一个类对象作为另一个类的属性
聚合关系 空心菱形 菱形在整体 箭头在部分 聚在一起 独立的生命周期 弱关系
组合关系 实心菱形 强关系 人与头 人挂了 头也没生命力了
继承关系 三角空心实线 类和类之间的关系 继承 子类指向父类
实现关系 三角空心虚线 虚 实现 指向要被实现的接口
看图 项目代码 看看UML图 快速理解项目
总结
-
定义
-
特点
-
分类
-
类图
-
时序图
-
记忆技巧 理解 多用
-
java设计模式精讲 debug方式+内存分析_图解Java设计模式之设计模式面试题
2020-11-22 15:30:30图解Java设计模式之设计模式面试题1.1 Java设计模式内容介绍1.1.1 先看几个经典的面试题1.1.2 设计模式的重要性1.1 Java设计模式内容介绍1.1.1 先看几个经典的面试题原型设计模式问题 :1)有请使用UML类图画出原型...图解Java设计模式之设计模式面试题
- 1.1 Java设计模式内容介绍
- 1.1.1 先看几个经典的面试题
- 1.1.2 设计模式的重要性
- 1.1 Java设计模式内容介绍
1.1 Java设计模式内容介绍
1.1.1 先看几个经典的面试题
- 原型设计模式问题 :
1)有请使用UML类图画出原型模式核心角色
2)原型设计模式的深拷贝和浅拷贝是什么。并写出深拷贝的两种方式的源码(重写clone方法实现深拷贝、使用序列化来实现深拷贝)
3)在Spring框架中哪里使用到原型模式,并对源码进行分析
beans.xml
<bean id="id01" class="com.demo.spring.bean.Monster" scope="prototype" />
4)Spring中原型bean的创建,就是原型模式的应用
5)代码分析 + Debug源码- 设计模式的七大原则 :要求 :
1)七大设计原则核心思想
2)能够以类图的说明设计原则
3)在项目实际开发中,你在哪里使用到来ocp原则设计模式常用的七大原则有 :
1)单一职责原则
2)接口隔离原则
3)依赖倒转原则
4)里氏替换原则
5)开闭原则ocp
6)迪米特法则7)合成复用原则
- 金融借贷平台项目 : 借贷平台的订单,有审核-发布-抢单等等步骤,随着操作的不同,会改变订单的状态,项目中的这个模块实现就会使用到状态模式,请你使用状态模式进行设计,并完成实际代码问题分析 :
这类代码难以应对变化,在添加一种状态时,我们需要手动添加if/else,在添加一种功能时,要对所有的状态进行判断。因此代码会变得越来越臃肿,并且一旦没有处理某个状态,便会发生极其严重的BUG,难以维护。
- 解释器设计模式
1)介绍解释器设计模式是什么?
2)画出解释器设计模式的UML类图,分析设计模式中的各个角色是什么?
3)请说明Spring的框架中,哪里使用到来解释器设计模式,并做源码级别的分析
解释器模式在Spring框架应用的源码剖析
1)Spring框架中SpelExpressionParser就使用到解释器模式
2)代码分析 + Debug源码 + 模式角色分析说明- 单例设计模式一共有几种实现方式?请分别用代码实现,并说明各个实现方式的优点和缺点?
单例设计模式一共有8种写法,后面会依次讲到
1)饿汉式 两种
2)懒汉式 三种
3)双重检查
4)静态内部类
5)枚举
1.1.2 设计模式的重要性
1)软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。这个术语是埃里希·伽玛等人在1990年代从建筑设计领域引入到计算机科学的
2)大厦 VS 简易房
3)拿实际工作经历来说,当一个项目开发完后,如果客户提出增新功能,怎么办?(可扩展性,使用设计模式,软件具有很好的扩展性)
4)如果项目开发完后,原来程序员离职,你接手维护该项目怎么办?(维护性【可读性、规范性】)
5)目前一线IT公司,都会问在实际项目中使用过什么设计模型,怎样使用的,解决来什么问题。
6)设计模式在软件中哪里?面向对象(oo) =》功能模块【设计模式 + 算法(数据结果)】 =》框架【使用到多种设计模式】=》架构【服务器集群】 -
《Java 设计模式精讲》笔记——第12章 适配器模式
2021-01-24 23:06:22本博客是本人在学习《Java 设计模式精讲》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。 本博客已标明出处,如有侵权请告知,马上删除。 1. 适配器模式讲解 定义:将一个类的接口转换成客户期望的另一个...声明:
本博客是本人在学习《Java 设计模式精讲》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。
本博客已标明出处,如有侵权请告知,马上删除。
1. 适配器模式讲解
- 定义:将一个类的接口转换成客户期望的另一个接口
- 使原本接口不兼容的类可以一起工作
- 类型:结构型
- 适用场景
- 已经存在的类,它的方法和需求不匹配时(方法结果相同或相似)
- 不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案
- 优点
- 能提高类的透明性和复用,现有的类复用但不需要改变
- 目标类和适配器类解耦,提高程序扩展性
- 符合开闭原则
- 缺点
- 适配器编写过程需要全面考虑,可能会增加系统的复杂性
- 增加系统代码可读的难度
- 拓展
- 对象适配器:符合合成复用原则,使用委托机制
- 类适配器:通过类继承来实现
- 相关设计模式
- 适配器模式和外观模式
- 适配器模式和外观模式都是对现有的类的封装
- 适配器模式是复用一个原有的接口,外观模式定义了新的接口
- 适配器模式是使两个原有的接口协同工作,外观模式则是在现有的系统中提供一个更为方便的访问入口
- 适配器模式和外观模式
2. 适配器模式 Coding
适配器模式分为对象适配器和类适配器,他们的区别在于对象适配器通过组合实现,类适配器通过继承实现,下面分别进行演示。
类适配器
-
创建一个被适配类
public class Adaptee { public void adapteeRequest() { System.out.println("被适配者的方法"); } }
-
创建目标方法的接口
public interface Target { void request(); }
-
创建接口实现类
public class ConcreteTarget implements Target { @Override public void request() { System.out.println("ConcreteTarget目标方法"); } }
-
创建适配器类,继承被适配类,实现目标方法接口
public class Adapter extends Adaptee implements Target { @Override public void request() { super.adapteeRequest(); } }
-
测试类
public class Test { public static void main(String[] args) { Target target = new ConcreteTarget(); target.request(); // 通过适配器实现 Target adapterTarget = new Adapter(); adapterTarget.request(); } }
运行结果:
ConcreteTarget目标方法 被适配者的方法
分析:当我们调用适配器类的目标方法时,实际调用的是被适配类中的方法。
现在类图如下所示:
对象适配器
还是上面的业务场景,使用对象适配器只需要修改适配器类。
适配器类不再继承被适配类,而是将被适配类作为属性组合到适配器中,然后通过对象来调用被适配类里面的方法
public class Adapter implements Target { private Adaptee adaptee = new Adaptee(); @Override public void request() { adaptee.adapteeRequest(); } }
现在类图如下所示:
下面我们再类引入一个生活场景:手机充电器的适配器,将 220V 的交流电转换成 5V 的直流电。
-
创建被适配的类,220V 的交流电类
public class AC220 { public int outputAC220V() { int output = 220; System.out.println("输出220V的交流电"+output+"V"); return output; } }
-
创建目标方法的接口,5V 的直流电类
public interface DC5 { int outputDC5V(); }
-
创建适配器类
public class PowerAdapter implements DC5 { private AC220 ac220 = new AC220(); @Override public int outputDC5V() { int adapterInput = ac220.outputAC220V(); /** 变压器 */ int adapterOutput = adapterInput / 44; System.out.println("通过PowerAdapter电源适配器输入AC"+adapterInput+"V"+"输出DC:"+adapterOutput+"V"); return adapterOutput; } }
-
测试类
public class Test { public static void main(String[]args){ DC5 dc5 = new PowerAdapter(); dc5.outputDC5V(); } }
运行结果:
输出220V的交流电220V 通过PowerAdapter电源适配器输入AC220V输出DC:5V
-
《Java 设计模式精讲》笔记——第16章 代理模式
2021-01-25 20:33:34本博客是本人在学习《Java 设计模式精讲》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。 本博客已标明出处,如有侵权请告知,马上删除。 1. 代理模式讲解 定义:为其他对象提供一种代理,以控制对这个... -
《Java 设计模式精讲》笔记——第19章 策略模式
2021-01-26 11:21:07本博客是本人在学习《Java 设计模式精讲》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。 本博客已标明出处,如有侵权请告知,马上删除。 1. 策略模式讲解 定义:定义了算法家族,分别封装起来,让它们... -
《Java 设计模式精讲》笔记——第21章 观察者模式
2021-01-26 13:29:45本博客是本人在学习《Java 设计模式精讲》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。 本博客已标明出处,如有侵权请告知,马上删除。 1. 观察者模式讲解 定义:定义了对象之间的一对多依赖,让多个... -
《Java 设计模式精讲》笔记——第4章 简单工厂模式
2021-01-24 11:57:33本博客是本人在学习《Java 设计模式精讲》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。 本博客已标明出处,如有侵权请告知,马上删除。 1. 简单工厂讲解 定义:由一个工厂对象决定创建出哪一种产品类的... -
《Java 设计模式精讲》笔记——第11章 装饰者模式
2021-01-24 18:38:46本博客是本人在学习《Java 设计模式精讲》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。 本博客已标明出处,如有侵权请告知,马上删除。 1. 装饰者模式讲解 定义:在不改变原有对象的基础之上,将功能... -
《Java 设计模式精讲》笔记——第6章 抽象工厂模式
2021-01-24 16:42:58本博客是本人在学习《Java 设计模式精讲》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。 本博客已标明出处,如有侵权请告知,马上删除。 1. 抽象工厂讲解 定义:抽象工厂模式提供一个创建一系列相关或... -
《Java 设计模式精讲》笔记——第5章 工厂方法模式
2021-01-24 15:06:14本博客是本人在学习《Java 设计模式精讲》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。 本博客已标明出处,如有侵权请告知,马上删除。 1. 工厂方法讲解 定义:定义一个创建对象的接口,但让实现这个... -
java设计模式精讲 第2章 UML急速入门
2018-12-11 11:02:42java设计模式精讲 第2章 UML急速入门2-1本章导航UML的定义UML的特点UML2.2的分类UML类图记忆技巧UML时序图2-2UML类图讲解2-3 详细案例讲解依赖关系:继承的关系组合关系关联关系聚合关系实现接口实现接口2 - 棒棒糖... -
Java设计模式精讲—慕课网—课程笔记4(第8章 单例模式)
2019-11-08 22:38:03Java设计模式精讲—慕课网—课程笔记3 8 单例模式讲解+Coding+源码解析 8.1 单例模式讲解 8.2 单例设计模式——懒汉式及多线程Debug实战 8.3 单例设计模式——DoubleCheck双重检查实战及原理解析 8.4 单例设计模式... -
Java设计模式精讲 Debug方式+内存分析[完整版]-28节
2020-06-22 14:21:03Java设计模式精讲 Debug方式+内存分析[完整版] 系统学习设计原则,设计模式,锤炼编码内功,赢取高薪 Offer 下载地址: https://download.csdn.net/download/weixin_38779390/12542938(资源正在审核) -
《Java 设计模式精讲》笔记——第3章 软件设计七大原则
2021-01-22 21:05:29本博客是本人在学习《Java 设计模式精讲》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。 本博客已标明出处,如有侵权请告知,马上删除。 1. 七大原则 开闭原则 依赖倒置原则 单一职责原则 接口隔离原则 ... -
java常用设计模式精讲_2019最新java设计模式精讲 Debug 方式+内存分析(28章全)
2021-03-12 19:47:29f __set__(self, instance, value):instance.__dict__[self.name] = value# Descriptor for enforcing typesclass Typed(Descriptor):expected_type = type(None)def __set__(self, instance, value):if not isinsta... -
java设计模式精讲 Debug 方式+内存分析-第2章 UML急速入门
2018-11-17 20:48:07@java设计模式精讲 Debug 方式+内存分析-第2章本章导航UML的定义UML的特点UML2.2的分类UML类图记忆技巧UML时序图UML类图讲解 本章导航 UML的定义 UML的特点 UML2.2的分类 结构式图形 行为式... -
击鼓传花java_Java设计模式精讲(一):责任链模式
2020-12-20 19:10:21前言这篇分享作为一个系列分享的第一篇,主要和大家一起学习一下java设计模式方面的基础,我们现在的安卓开发主要还是基于java语言,所以掌握java本身的基础也是非常重要的。在j2ee、web和安卓其他一些java程序开发... -
Java设计模式精讲—慕课网—课程笔记2(第3章 软件设计七大原则)
2019-10-22 18:29:57Java设计模式精讲—慕课网—课程笔记23 软件设计七大原则3.1 本章导航3.2 开闭原则+coding3.4 依赖倒置原则+coding3.5 单一职责原则+coding3.6 接口隔离原则+coding3.7 迪米特原则+coding3.8 里氏替换原则+coding3.9... -
Java设计模式精讲—课程笔记7(第15章 桥接模式 + 第16章 代理模式 + 第17章 模板方法模式)
2019-11-23 16:49:16Java设计模式精讲—课程笔记7 15 桥接模式讲解+Coding+源码解析 15.1 桥接模式讲解 15.2 桥接模式Coding 15.3 桥接模式源码解析(jdk) 16 代理模式讲解+Coding+源码解析 16.1 代理模式讲解 16.2 代理模式Coding-... -
Java设计模式精讲—课程笔记5(第9章 原型模式 + 第10章 外观模式 + 第11章 装饰者模式)
2019-11-19 22:38:02Java设计模式精讲—慕课网—课程笔记5 9 原型模式讲解+Coding+源码解析 9.1 原型模式讲解 9.2 原型模式coding 9.3 原型模式coding—克隆破坏单例 9.4 原型模式源码解析 10 外观模式讲解+Coding+源码解析 10.1 外观... -
Java设计模式精讲—课程笔记6(第12章 适配器模式 + 第13章 享元模式 + 第14章 组合模式)
2019-11-21 17:33:59Java设计模式精讲—慕课网—课程笔记6 12 适配器模式讲解+Coding+源码解析 12.1 适配器模式讲解 12.2 适配器模式coding 12.3 适配器模式源码解析(jdk+spring+springjpa+spingmvc) 13 享元模式讲解+Coding+源码解析... -
Java设计模式精讲—课程笔记8(第18章 迭代器模式 + 第19章 策略模式 + 第20章 解释器模式)
2019-11-23 19:30:30Java设计模式精讲—课程笔记818 迭代器模式讲解+源码解析18.1 迭代器模式讲解18.2 迭代器模式代码解析18.3 迭代器模式源码解析(jdk+mybatis)19 策略模式讲解+Coding+源码解析19.1 策略模式讲解19.2 策略模式coding... -
Java设计模式精讲—课程笔记9(第21章 观察者模式 + 第22章 备忘录模式 + 第23章 命令模式 + 第24章 中介者...
2019-11-28 23:05:14Java设计模式精讲—课程笔记921 观察者模式讲解+Coding+源码解析21.1 观察者模式讲解21.2 观察者模式coding21.3 观察者模式源码解析-jdk-guava22 备忘录模式讲解+Coding+源码解析22.1 备忘录模式讲解22.2 备忘录模式... -
Java设计模式精讲—课程笔记10(第25章 责任链模式 + 第26章 访问者模式 + 第27章 状态模式 + 第28章 课程...
2019-11-29 16:55:33Java设计模式精讲—课程笔记1025 责任链模式讲解+Coding+源码解析25.1 责任链模式讲解25.2 责任链模式coding25.3 责任链模式源码-servlet26 访问者模式讲解+源码解析26.1 访问者模式讲解26.2 访问者模式coding26.3 ...