Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

时间:2021-10-13 21:58:38

从网络上找的设计模式, 很全面,只要把UML类图看懂了, 照着类图将代码实现是很容易的事情.

步骤: 先看懂类图, 然后将代码实现, 之后再看文字

http://c.biancheng.net/design_pattern/

https://www.runoob.com/design-pattern/abstract-factory-pattern.html

7大设计原则:

1: 单一职责原则: 类应该只有一个职责,或者功能

2: 接口隔离原则: 一个类不应该依赖与他不相关,不需要的接口, 一个类对另一个类的依赖应该建立在最小的接口上

3: 依赖倒置原则: 依赖抽象不依赖具体,思想是:面向接口编程

4: 里氏替换原则: java中的继承有弊端, 少用继承, 多使用聚合,组合,依赖, 因为子类继承后,很容易不小心将父类中的方法重写, 而子类不知道,调父类方法时候,容易混淆, 换句话就是: 所有使用父类方

法的地方,也能透明的使用其子类的对象, 子类尽量不要重写父类的方法, 可以将父类和子类都继承一个更通俗的父类,

5: 开闭原则(ocp原则): 对扩展开放(提供方), 对修改关闭(使用方)

6: 迪米特原则: 最少知道原则, 一个类对自己依赖的类知道越少越好,被依赖的类尽量将逻辑都封装到类中,只提供外一个入口就好, 又叫: 只和直接朋友通信,(直接朋友:成员变量,方法入参, 方法返回

值中的类都是直接朋友, 局部变量中的类不是直接朋友, 也就是说陌生的类,不要以局部变量的方式出现在类中)

7: 合成复用原则: 尽量使用聚合,组合的方式, 少用继承, 这样做目的是 松耦合

一: 1.1:简单工厂模式(又叫静态工厂模式): 是将各种对象的创建都交给一个工厂类, client要使用各种对象时候,只需要在client中聚合这个工厂类即可,

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

比如这个图中,胡椒披萨,榴莲披萨,原味披萨, 都有一个共同的基类Pizza, 工厂类SimpleFactory 根据不同类型返回对应的披萨对象,, OrderPizza这个就是client类, 在OrderPizza类中聚合工厂类即可, 就可以根据不同类型创造不同口味的披萨了


1.2: 工厂方法模式: 假如有北京胡椒披萨,北京榴莲披萨,北京原味披萨, 伦敦胡椒披萨,伦敦榴莲披萨,伦敦原味披萨. 此时使用简单工厂模式是不合适的, 等于在这个工厂类中,要分别创建这6个披萨对象, 修改多,维护性,扩展性差 .解决方法: 简单工厂模式是创建了一个工厂类, 工厂方法模式,是创建一个抽象工厂类,他的实现是北京工厂类, 伦敦工厂类, 在实现类中完成对象的创建,

这样等于是,将对象的创建交给子类取实现.uml类图如下:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

1.3: 抽象工厂模式: 工厂方法模式是创建了一个 抽象工厂类,让子类取实现,完成对象创建, 很相似 抽象工厂模式是定义一个接口, 对象的创建在子类中完成.client中聚合该接口类,uml类图如下

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

工厂模式再JDK源码中的应用

  Calendar date = Calendar.getInstance();

  public static Calendar getInstance(){
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}

再点进去

  private static Calendar createCalendar(TimeZone zone,Locale aLocale){
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
}
Calendar cal = null;
if (aLocale.hasExtensions()) {
//这里根据时区不同,来创建不同的对象
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
if (cal == null) {
// If no known calendar type is explicitly specified,
// perform the traditional way to create a Calendar:
// create a BuddhistCalendar for th_TH locale,
// a JapaneseImperialCalendar for ja_JP_JP locale, or
// a GregorianCalendar for any other locales.
// NOTE: The language, country and variant strings are interned.
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
}

二: 原型模式: 原型模式就是将一个对象复制出另一个对象来,除了内存地址不同,其余都相同, 使用Object类中的clone方法, 如果一个对象中的属性都是基本数据类型, 使用clone方法就可以实现对象的复制, 如果该对象中的属性,有引用数据类型(数组,另一个对象,list,)此时使用clone方法,不能实现对象的完全复制, 因为 引用数据类型,使用clone方法,在内存中只是指针的引用,并没有重新复制出相同的对象来,,,, 建议使用流序列化的方式实现深拷贝

原型模式在spring中的应用, spring中的bean的创建, xml文件中配置 这里的 scope="prototype"就是指对象多例模式, 其实就是原型模式,复制一模一样的对象

三: 建造者模式: 将复杂对象的建造过程 抽象出来, 从而他的实现类可以构造出不同属性的对象, 用户只需要指定复杂对象的类型和内容,就可以建造他们,不需要知道具体的建造过程. 比如房子建造过程: 打地基,砌墙,封顶, 他的实现类:普通房子实现类, 创建的对象:普通房子,地基150cm,墙厚15cm,顶是茅草顶, 另一个实现类:豪宅,创建的对象: 地基300cm,墙厚50cm,顶是金砖顶.

有四个角色:

1:产品(product)

2:抽象建造者(builder), 创建一个product对象的各个部件指定的接口或抽象类

3:具体建造者(concreateBuilder) 实现接口,构建和装配各个配件

4:指挥者(director) , 构建一个使用 builder接口的对象,它主要创建一个复杂对象, 隔离了客户与产品的制造过程, 负责控制产品的制造流程

uml类图如下:

该图中,产品product 是组合到 builder抽象类中的,这样builder的实现类,都可以拿到product,从而对其属性,方法进行各自的实现, builder 和 director(指挥者)的关系是聚合, 同时,director类中,会有一个总的build方法,作为对外提供的接口, client端使用的时候,只需要使用 director类的 builder 方法,就可建造不同类型的产品了.

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用


建造者模式在 JDK 中的应用, 比如:StringBuilder

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

建造者模式和 抽象工厂模式对比, 建造者模式是隔离了客户和 产品建造过程, 而抽象工厂模式,没有隔离,在client中调用时候,需要具体实现者一步一步建造产品, 这样如果再有一个房子的产品,地基500cm,墙600cm,没有顶, 相对于建造者模式来说,修改很容易, 而抽象工厂模式来说,相当于又把建造流程写了一遍,不利于维护和扩展 uml对比如下

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

四: 适配器模式: 目的是兼容, 将某个类的接口转换成客户期望的另一个接口表示,让原本因为接口不匹配而不能一起工作的二个类可以协同工作, 从客户的角度看不到适配过程,感觉只是和目标类接口交互,uml类图如下, 类之间的关系 Voltage5V这个是适配器接口,Voltage220V是被适配类, VoltageAdapter是适配器实现类, 实现适配器接口,并继承被适配类,

类适配器UML类图

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

之前说过继承不好,可以用聚合来代替, 对象适配器UML类图如下:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

类适配器模式, 对象适配器模式, 都是适配器接口, 而 接口适配器模式, 是将适配器接口做成抽象类, 被适配类(220V)做成接口, 抽象类实现该接口, 这样client使用的时候,直接使用抽象类,并重写方法就可以了,很简单很灵活, 接口适配器模式UML类图如下:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

适配器模式在SpringMVC 中的应用: 相信这个图我们都很熟悉了,

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

client发送请求到 DispatchServlet, ,,,,请求执行Hander, 这个请求就是发给了处理器适配器,HandlerAdapter, 因为处理器的类型很多,spring定义这个接口,使得每一种Controller都有对应的适配器实现类, 适配器代替controller执行相应的方法, controller和 适配器的类图如下:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

五:桥接模式: 就是将 抽象化(Abstraction) 和实现化(inplermentation) 分开,使二者可以独立变化, UMl类图如下:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用,

一个很常见的场景是:发送提示消息, 消息类型有 普通消息, 加急消息,特急消息, 消息发送手段又分为: 系统内短消息, 手机短消息, email

使用桥接模式就是,将消息类型 和 消息发送手段分开, 让他们独立变化, 看下图

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

实现类接口 和抽象类的关系是聚合, client调用的时候,创建了抽象类实例化对象,设置已经聚合对象 这样会很灵活, 消息类型和 发送手段结合,,,既能满足需求, 也避免了类爆炸,

再比如: 手机方式: 折叠,直板,侧滑, 手机品牌:小米,vivol,华为

使用桥接模式的UML类图为:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用


桥接模式在 JDBC源码中的使用

1:JDBC驱动程序, 2:消息管理, 3: 银行的转账系统(网上转账,柜台转账,ATM转账)(普通用户,金卡用户,vip用户)

JDBC类图如下,

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

六: 装饰者模式: 动态的将新功能附加到对象上, 在对象功能扩展上, 比继承更灵活,也体现了ocp原则, , 也可以理解为 实现了多种组合

很多人分不清装饰者模式 和代理模式的区别, 装饰者模式,是对同一个对象的功能加强, 代理模式是重新new了一个对象,这个新对象调用 被调用者的方法功能.

装饰者模式的UML类图如下:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

可以看到, 作料的实现类中,都聚合了 饮料类, 这个饮料类属性也可以在 作料抽象类中, 作料的实现类使用的时候,直接 supper就可以了

装饰者模式在 JDK中的应用: I/O InputStream UML类图如下

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

七:组合模式: 又叫部分整体模式, 他创建了对象组的树形结构,将对象组成树状结构来展示 部分-整体 的层次关系

UML类图:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

比如: 展示一个学校院系结构, 一个学校有多个学院,一个学院有多个系, 学校,学院,系,都继承Component,抽象类中,增删方法. 系就是叶子节点(Leaf), 学校, 学院就是(Composite)子节点, 并且在子节点类中维护有一个存储方式List , 对应的UML类图为:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用


组合模式在源码中的应用, 比如HashMap, 点进去后可以看到: 抽象类是Map 接口, 叶子节点是 Node(也实现了 Map接口), 子节点是 HashMap(也实现了Map接口,并在HashMap中维护了一个存储方式 node的数组:Node<K,V>[] table),对应的UML类图如下:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

这里只是解析了HashMap的组合模式,平常代码过程中,也要使用组合模式, 先定义一个抽象类或接口, 抽象类中定义一些通用功能, 接着定义一个中间构件(子节点)实现抽象类/接口,重写通用功能,并在子节点中维护一个存储结构,map,list 都可以, 最后定义一个叶子节点,同样继承/实现抽象构件,里面方法可以根据特殊需要重写.

八: 外观模式: 打个比方: 电脑(包含了cpu, 硬盘,内存,屏幕)开机/关机,要依次将这四个部分开机/关机, 而实际上,我们只是点了开机按钮, 是由于电脑已经帮我们处理好了, 这四个部分就相当于 子系统角色, 开机按钮,就是电脑提供给我们的统一界面, 相当于外观角色 . 外观模式就是 定义一个高层的接口/类(外观角色), 给各个子系统一群接口(将各个子系统类,聚合到外观接口中),提供一个统一的对外访问接口, 客户直接和外观角色交互, 不和各个子系统的一群接口交互, 这样做避免了调用混乱, 对客户来说使用简单. 外观类中提供一个对外方法(方法中,各个子系统类方法依次执行),

解决了 多个子系统接口调用混乱的问题, 起到简化用户操作的目的, 比如java 的 三层开发, 也是外观模式的应用,

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

外观模式在源码中的应用:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用


九: 享元模式: 分享对象模式: 各种各样的池技术, 常量池,线程池,连接池,缓冲池等等, 比如网络围棋,棋子对象,如果都要创建的话,一盘棋要创建几百个对象, 数百人都在线,又要创建多少对象,服务器内存才够, 显然这里的棋子对象 很相似, 只是颜色和 坐标不同而已, 此时就用到了池技术(享元模式)之后,只需要二个对象即可,减小服务器内存占用, 享元模式,要区分对象的内部状态, 和外部状态, 显然,对于棋子来说,颜色是内部状态, 坐标是外部状态,

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

享元模式详解:

https://www.cnblogs.com/adamjwh/p/9070107.html

十: 代理模式:

静态代理: 需要代理对象,和被代理对象,都实现相同的接口或者继承相同父类, 并且,将被代理对象 聚合到代理类中, 这样代理类,能重写父类的方法,在方法中,又因为聚合了被代理对象, 所以可以针对被代理对象的方法,实现前置, 后置修改. UML类图如下:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

JDK代理: 是 java 帮我们创建了目标对象的代理对象, 也是需要被代理对象有个接口, 利用Proxy.newProxyInstance(var1,var2,var3) 方法创建代理对象, var1:被代理对象的类加载器 classLoader, var2:被代理对象的接口类型, var3: InvocationHandler 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入

cglib动态代理:不需要父类接口, 只需要被代理对象实现 MethodInterceptor接口, 重写 intercept方法, 这个方法相当于方法拦截器, 可以在方法中,调用目标方法, 前置处理, 后置处理.

相当于给被代理对象,生 了一个儿子,这个儿子就是代理对象,

https://blog.****.net/P19777/article/details/103998918


十一: 模板方法模式: 这个比较简单, 抽象类中,定义整个流程的多个方法(抽象方法), 这些方法推迟到子类中实现,从而实现个性化

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

模板方法模式在 SpringIOC容器初始化时候用到了模板方法模式, mybatis中的 BaseExcutor抽象类中用了模板方法模式, 这个抽象类实现了Excutor接口, Excutor接口中定义了一系列 操作数据库的方法:比如查询,更新,创建缓存key,删除缓存,获取事务,关闭等等方法, BaseExcutor这个抽象类中实现了一些 共性的方法比如 缓存管理,事务管理方法,有四个方法,让他的子类去重写,比如:doUpdate() 方法、doQuery() 方法、doQueryCursor() 方法、doFlushStatement() 方法, 他的UML类图如下:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用


十二:命令模式:

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

十三: 访问者模式: 这个不太明白啊

十四: 迭代器模式: 对外提供统一的集合迭代接口, 用统一的方法遍历集合元素, 不暴露内部结构

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

十五: 观察者模式: 又叫发布-订阅模式

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

十六: 中介者模式: 中介者模式: 用一个中介对象来封装一系列的对象交互, 中介者是各个对象不需要显式的相互引用, 从而使其松耦合,而且可以独立的改变他们之间的交互, 比如MVC模式.C(Controller控制器) 是M(Model模型)和V(view视图)的中介者,在前后端交互时起到了中间人作用, 中介者明细的特征是,每个同事对象都聚合了中介者, 中介者同时也聚合了每一个同事

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用的更多相关文章

  1. java的23种设计模式之建造者模式

    场景和本质 场景 本质 案例 原理 应用场景 场景和本质 场景 我们要建造一个复杂的产品.比如:神州飞船,Iphone.这个复杂的产品的创建.有这样一个问题需要处理:装配这些子组件是不是有个步骤问题? ...

  2. 从追MM谈Java的23种设计模式&lpar;转&rpar;

    从追MM谈Java的23种设计模式    这个是从某个文章转载过来的.但是忘了原文链接.如果知道的,我追加一下. 1.FACTORY-追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西 ...

  3. 从追MM谈Java的23种设计模式

    从追MM谈Java的23种设计模式 1.FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯 德基,只管向服务员说“来四个鸡 ...

  4. Java之——23种设计模式汇总

    在软件开发的历程中,正是无数前辈们本着追求完美的架构设计和代码设计的初心.经过无数前辈们的探索和努力,逐渐形成了一系列的设计原则和设计模式. 对于Java语言来说,通常包含有6大设计原则和23种设计模 ...

  5. JAVA:23种设计模式详解(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  6. Java实现23种设计模式

    一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接 ...

  7. Java开发23种设计模式之禅

    六大原则 23种设计模式: 总体来说设计模式分为三大类: *创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. *结构型模式,共七种:适配器模式.装饰器模式.代理模式.外 ...

  8. Java 开发23种设计模式

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  9. Java的23种设计模式(转)

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...

  10. Java的23种设计模式&lt&semi;一&gt&semi;

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代 码可靠性. 毫无疑问,设计模式 ...

随机推荐

  1. JS中的函数&lpar;二&rpar;:函数参数(你可能不知道的参数传递)

    前言: 函数分为有参有返回值,有参无返回值,无参无返回值,无参有返回值:那么对于无参数的函数你想使用函数的调用怎么办呢?如果你想封装一个代码,实现多种功能,但是形参大于实参或者实参大于形参又该如何?本 ...

  2. angular源码分析:angular中jqLite的实现——你可以丢掉jQuery了

    一.从function JQLite(element)函数开始. function JQLite(element) { if (element instanceof JQLite) { //情况1 r ...

  3. Java 常用排序算法&sol;程序员必须掌握的 8大排序算法

    Java 常用排序算法/程序员必须掌握的 8大排序算法 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配 ...

  4. openstack 在线repo

    https://repos.fedorapeople.org/repos/openstack/openstack-kilo/

  5. SQLServer Alter 修改表的列名的解决

    解决:在SQLServer中修改表的列名,可以调用存储过程sp_rename. [sql]use Test;--使用数据库  sp_rename 'd_s_t.avg_grade','avg_g',' ...

  6. C&plus;&plus;对象模型笔记之程序设计模型

    C++程序设计模型支持三种程序设计模型 1.程序模型(procedural model) 可以理解为过程化模型,就像C一样 2.抽象数据类型模型(ADT) 数据结构教材里有说过,查了下资料也不是很明确 ...

  7. 阿里云SLB出现502 Bad Gateway 错误排查解决方法

    502 Bad Gateway The proxy server received an invalid response from an upstream server. 原本系统是通过一个SLB转 ...

  8. Flv视频格式如何转换成MP4格式

    如何将flv视频格式转换成MP4格式呢?随着现在视频格式的不断多样化,视频格式转换的问题也成了现在生活中常见的问题,那么我们应该怎样将flv视频格式转换成MP4格式呢?下面我们就一起来看一下吧. 操作 ...

  9. 【Java深入研究】4、fail-fast机制

    在JDK的Collection中我们时常会看到类似于这样的话: 例如,ArrayList: 注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证.快速失 ...

  10. 阿里八八Alpha阶段Scrum&lpar;9&sol;12&rpar;

    今日进度 叶文滔: 成功完成多级悬浮按钮,并添加与日程输入界面的连接.debug了一些对接产生的问题 黄梅玲: 合并单日项目至多日.获取json数据 王国超: 完成了初步的多日界面,pull至项目.进 ...