1 创建型模式
1.1 单例模式
为了避免不一致的状态,避免政出多头。
某些实例的创建需要很大的开销,一个就够了,为了节约资源所以做成单例模式。
Runtime
Runtime 类代表着Java程序的运行时环境,每个Java程序都有一个Runtime实例,该类会被自动创建,我们可以通过Runtime.getRuntime()
方法来获取当前程序的Runtime实例。
//获取可用内存
long value = Runtime.getRuntime().freeMemory();
//获取jvm的总数量,该值会不断的变化
long totalMemory = Runtime.getRuntime().totalMemory();
//获取jvm 可以最大使用的内存数量,如果没有被限制 返回 Long.MAX_VALUE;
long maxMemory = Runtime.getRuntime().maxMemory();
// 获取jvm可用的处理器核心的数量
int value = Runtime.getRuntime().availableProcessors();
执行系统命令
public static void commend() {
try {
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("calc");
} catch (Exception e) {
e.printStackTrace();
}
}
DateFormat/NumberFormat等
Date date = new Date();
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM); //省略了Locale对象,默认中文环境
String dateStr = df.format(date);
System.out.println(dateStr);
1.2 工厂方法
它的作用是:
- 隐藏具体类名,很多类隐藏得很深的,而且可能会在后续版本换掉
- 避免你辛苦的准备构造方法的参数
- 这个工厂类可以被配置成其它类
- 这个工厂对象可以被传递
最重要的是:new一个确切的对象其实也是一种硬编码!!!工厂方法类封装了复杂的对象创建的逻辑,也实现了一部分解耦。让对象的创建更加直观和简单。
- java.lang.Proxy#newProxyInstance()
- java.lang.Object#toString()
- java.lang.Class#newInstance()
- java.lang.reflect.Array#newInstance()
- java.lang.reflect.Constructor#newInstance()
- java.lang.Boolean#valueOf(String)
- java.lang.Class#forName()
普通工厂模式
就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建,好处就是创建实例更简单一些。
多个工厂方法模式
传递一个参数进去,参数不一样,创建不同的实例。
静态工厂方法模式
将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
JDK中体现:
(1)Integer.valueOf
(2)Class.forName
1.3 抽象工厂
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。工厂类都实现同一个接口,不同的工厂类创建不同的实例。
抽象工厂模式提供了一个协议来生成一系列的相关或者独立的对象,而不用指定具体对象的类型。它使得应用程序能够和使用的框架的具体实现进行解耦。这在JDK或者许多框架比如Spring中都随处可见。它们也很容易识别,一个创建新对象的方法,返回的却是接口或者抽象类的,就是抽象工厂模式了。
- java.util.Calendar#getInstance()
- java.util.Arrays#asList()
- java.util.ResourceBundle#getBundle()
- java.sql.DriverManager#getConnection()
- java.sql.Connection#createStatement()
- java.sql.Statement#executeQuery()
- java.text.NumberFormat#getInstance()
- javax.xml.transform.TransformerFactory#newInstance()
1.4 建造者模式
建造者模式定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
使用场景:
1、需要生成的对象具有复杂的内部结构。
2、需要生成的对象内部属性本身相互依赖。
与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。
//产品构建与组装方法
public Product construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
在Director的construct方法中,build是有顺序的。
定义了一个新的类来构建另一个类的实例,以简化复杂对象的创建。建造模式通常也使用方法链接来实现。
- java.lang.StringBuilder#append()
- java.lang.StringBuffer#append()
- java.sql.PreparedStatement
- javax.swing.GroupLayout.Group#addComponent()
1.5 原型模式
原型模式 (Prototype)用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。只要实现Cloneable接口,然后重写Object类中的clone方法就可以构造一个原型类,在使用的时候就是调用它的clone方法。
当要实例化的类是在运行时刻指定时,例如,通过动态装载。为了避免创建一个与产品类层次平行的工厂类层次时。当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
使用原型模式创建对象比直接new一个对象在性能上好得多,因为Object类的clone()方法是一个native方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
JDK中体现:Object.clone;Cloneable
2 结构型模式
2.1 组合模式
将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。组合模式让你可以优化处理递归或分级数据结构。
2.2 代理模式
代理模式是常用的结构型设计模式之一,当无法直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,所访问的真实对象与代理对象需要实现相同的接口。根据代理模式的使用目的不同,代理模式又可以分为多种类型,例如保护代理、远程代理、虚拟代理、缓冲代理等,它们应用于不同的场合,满足用户的不同需求。
JDK中体现:
(1)java.lang.reflect.Proxy
(2)cglib代理
(3)RMI
客户调用本地的方法,本地的方法调用远程的方法。 本地方法就是“代理”。“代理”处理所有网络通信的低层细节。
2.3 外观模式
为多个业务类的调用提供了统一的入口,简化了类与类之间的交互。
Tomcat中有很多场景都使用到了外观模式,因为Tomcat中有很多不同的组件,每个组件需要相互通信,但又不能将自己内部数据过多地暴露给其他组件。用外观模式隔离数据是个很好的方法。
2.4 适配器模式
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
JDK中体现:
(1)java.io.InputStreamReader(InputStream)
(2)java.io.OutputStreamWriter(OutputStream)
2.5 装饰器模式
动态地给一个对象添加一些额外的职责,动态扩展。装饰器模式具有如下的特征:
- 它必须持有一个被装饰的对象(作为成员变量)。
- 它必须拥有与被装饰对象相同的接口(多态调用、扩展需要)。
- 它可以给被装饰对象添加额外的功能。
总结:保持接口,动态增强性能。动态的给一个对象附加额外的功能,这也是子类的一种替代方式。
java.io包
由于java I/O库需要很多性能的各种组合,如果这些性能都是用继承来实现,那么每一种组合都需要一个类,大量重复类。首先,需要理解java I/O库是由一些原始流处理器和围绕它的装饰流处理器(装饰器,动态扩展原始类性能)所组成的。以FilterInputStream过滤输入流的子类为例,这个类的子类包括以下几种:
- java.io.BufferedInputStream(InputStream):用来从硬盘将数据读入到一个内存缓冲区中,并从缓冲区提供数据。
- java.io.DataInputStream(InputStream):提供基于多字节的读取方法,可以读取原始类型的数据。
- LineNumberInputStream:提供带有行计数功能的过滤输入流。
- PushbackInputStream:提供特殊的功能,可以将已经读取的字节“推回”到输入流中。
- java.io.BufferedOutputStream(OutputStream)
- java.util.zip.ZipOutputStream(OutputStream)
Collections
还有java.util.Collections#synchronizedList(List)
2.6 享元模式
避免对象数量太多,避免系统中出现大量相同或相似的对象,所以通过共享技术实现对象的复用。
JDK中体现:
(1)Integer.valueOf(int i);Character.valueOf(char c)
(2)String常量池
2.7 桥接模式
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。
以画笔
举例,画笔有不同种类,绘画又有不同颜色
,画笔的模型的抽象部分就是笔
,它继承绘画
这个接口,颜色
则作为一个接口,作为一个成员对象组合到笔
这个类中。即抽象维度用继承扩展,另一个维度作为其中的一个成员,使用接口。
3 行为型模式
3.1 策略模式
写代码时总会出很多的if…else,或者case。如果在一个条件语句中又包含了多个条件语句就会使得代码变得臃肿,维护的成本也会加大,而策略模式就能较好的解决这个问题。策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户变化。
JDK中的体现:ThreadPoolExecutor中的四种拒绝策略
3.2 模板方法模式
核心:处理某个流程的代码已经都具备,但是其中某个节点的代码暂时不能确定。因此,我们采用工厂方法模式,将这个节点的代码实现转移给子类完成。即:处理步骤在父类中定义好,具体的实现延迟到子类中定义。说白了,就是将一些相同操作的代码,封装成一个算法的骨架。核心的部分留在子类中操作,在父类中只把那些骨架做好。
Spring JdbcTemplate
为了使 JDBC 更加易于使用,Spring 在 JDBCAPI 上定义了一个抽象层, 以此建立一个JDBC存取框架.
作为 SpringJDBC 框架的核心, JDBC 模板的设计目的是为不同类型的JDBC操作提供模板方法. 每个模板方法都能控制整个过程,并允许覆盖过程中的特定任务.通过这种方式,可以在尽可能保留灵活性的情况下,将数据库存取的工作量降到最低.
JdbcTemplate主要提供以下五类方法:
execute
方法:可以用于执行任何SQL语句,一般用于执行DDL语句;update
方法及batchUpdate
方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;query
方法及queryForXXX
方法:用于执行查询相关语句;call
方法:用于执行存储过程、函数相关语句。
3.3 观察者模式
它使得一个对象可以灵活的将消息发送给感兴趣的对象。
Lisenter
- java.util.EventListener
- javax.servlet.http.HttpSessionBindingListener
- javax.servlet.http.HttpSessionAttributeListener
- javax.faces.event.PhaseListener
3.4 迭代子模式
迭代子模式又叫游标(Cursor)模式,是对象的行为模式。迭代子模式可以顺序地访问一个聚集中的元素而不必暴露聚集的内部表象(internal representation)。
JDK中体现:Iterator、Enumeration接口
3.5 责任链模式
请求会被链上的对象处理,但是客户端不知道请求会被哪些对象处理
JDK中体现:
(1)java.util.logging.Logger会将log委托给parent logger
(2)ClassLoader的委托模型
(3)Spring中的过滤器和拦截器
3.6 命令模式
作用:
(1)封装操作,使接口一致
(2)将调用者和接收者在空间和时间上解耦合
(3)将操作封装到对象内,以便存储,传递和返回。
JDK中体现:Runnable;Callable;ThreadPoolExecutor
3.7 备忘录模式
作用:保持对象状态,需要时可恢复
3.8 状态模式
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。
与策略模式的不同
状态模式的的思想是,状态之间的切换,在状态A执行完毕后自己控制状态指向状态B。状态模式是不停的切换状态执行。
策略模式的思想上是,考虑多种不同的业务规则将不同的算法封装起来,便于调用者选择调用。策略模式只是条件选择执行一次。
例子:数据库的Connection对象
3.9 访问者模式
访问者模式的基本想法是,软件系统中拥有一个由许多对象构成的、比较稳定的对象结构,这些对象的类都拥有一个 accept 方法用来接受访问者对象的访问。访问者是一个接口,它拥有一个 visit 方法,这个方法对访问到的对象结构中不同类型的元素做出不同的处理。在对象结构的一次访问过程中,我们遍历整个对象结构,对每一个元素都实施 accept 方法,在每一个元素的 accept 方法中会调用访问者的 visit 方法,从而使访问者得以处理对象结构的每一个元素,我们可以针对对象结构设计不同的访问者类来完成不同的操作,达到区别对待的效果。
3.10 中介者模式
通过使用一个中间对象来进行消息分发以及减少类之间的直接依赖。
- java.util.Timer
- java.util.concurrent.Executor#execute()
- java.util.concurrent.ExecutorService#submit()
- java.lang.reflect.Method#invoke()
3.11 解释器模式
这个模式通常定义了一个语言的语法,然后解析相应语法的语句。
- java.util.Pattern
- java.text.Normalizer
- java.text.Format