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

从网络上找的设计模式, 很全面,只要把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.csdn.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种设计模式全面解析(超级详细)以及在源码中的应用

上一篇:WPF 4 DataGrid 控件(自定义样式篇)


下一篇:剑指Offer:从第一个字符串中删除第二个字符串中出现过的所有字符