Java的23种设计模式
关于类的说明
http://c.biancheng.net/view/8375.html
单例模式
什么是单例模式:一个类只能有一个实例对象
具体实现:将构造方法私有化,本类中实例化,设计一个方法来进行实例化即可
懒汉式,单例模式
/**
* 静态属性为所有对象所共享的,通过类直接调用
* 不足:在多线程中存在多个对象,线程不安全
* 懒汉式,单例模式
*/
public class Single {
private Single(){}
//只可以实例化一次,设置静态属性
private static Single single;
public static Single getInstance(){
if (single == null)
single = new Single();
return single;
}
}
饿汉式,单例模式
/**
* 饿汉式,单例模式
* 不足:
* 1、类加载就会创建对象,始终该类不管是否使用都会存在一个对象
* 2、创建对象无法传递参数
*/
public class HungrySingleton {
//当创建对象时,只会创建一次
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return instance;
}
}
通过懒汉式衍生的单例模式,可以防止反射
解决了每次必先创建一个对象
public class HungrySingleton {
private static HungrySingleton hungrySingleton;
static {
try {
hungrySingleton = new HungrySingleton();
} catch (Exception e) {
e.printStackTrace();
}
}
private HungrySingleton() throws Exception {
if (hungrySingleton != null)
throw new Exception("该类只能实例化一次");
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
双层条件校验的单例模式
/**
* 双层校验,单例模式,线程安全
*/
public class DCLSingleton {
/**volatile,让静态属性值立刻可见*/
private volatile static DCLSingleton instance;
private DCLSingleton(){}
public static DCLSingleton getInstance() {
//先进行判断对象是否有值,否则已经有值了还是在等待,会造成线程堵塞
if (instance == null)
synchronized (DCLSingleton.class){
if (instance == null)
instance = new DCLSingleton();
}
return instance;
}
}
静态内部类实现单例模式
/**
* 静态内部类,单例模式,
* 线程安全,解决饿汉式中无论如何都存在一个对象问题
*/
public class StaticInnerSingleton {
private StaticInnerSingleton(){}
public static StaticInnerSingleton getInstance(){
return InnerClass.instance;
}
/**
* 静态内部类中用饿汉式的写法
*/
private static class InnerClass{
private static StaticInnerSingleton instance = new StaticInnerSingleton();
}
}
对单例模式进行测试
测试类
开多个线程,在每个进程里面进行创建多个单例模式,比较hascode码是否有不同
public class SingleTest {
public static void main(String[] args) {
// Single single = Single.getInstance();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
for (int j = 0; j < 10; j++) {
System.out.println(Single.getInstance());
}
}).start();
}
}
}
使用枚举写的单例模式
可以防止反射,序列化,克隆
/**
* 枚举,单例,线程安全,可以防止反射,序列化,克隆
*/
public enum EnumSingleton {
INSTANCE;
}
简单工厂模式
简单工厂模式有一个具体的工厂类,可以生成多个不同的产品,属于创建型设计模式
工厂类包含逻辑判断,使用多态进行的创建实例
简单工厂的优点
工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
客户端无需知道所创建具体产品的类名,只需知道参数即可。
也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类
简单工厂的缺点
简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。
该方法就是在一个类中集中进行创建,有时候若是出现了异常,整个类就会直接停止
工厂模式
具体实现方法:就是每个对象都可以有一个具体的方法进行创建,不会造成高聚合
工厂模式优点
用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
工厂模式缺点
类的个数容易过多,增加复杂度
增加了系统的抽象性和理解难度
抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决
抽象工厂:在同一个工厂里面,可以制造多种产品,让他们成为一个产品族
在抽象工厂里面,生产的是同一个产品等级的产品
代理模式
由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
代理模式的优点
代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
代理对象可以扩展目标对象的功能;
代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性
代理模式的缺点
代理模式会造成系统设计中类的数量增加
在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
增加了系统的复杂度
动态代理模式
动态代理必须实现接口
主要实现的类
/**
* 传入目标对象,使用反射机制动态创建代理对象
* @param targetObject
* @return
*/
public Object createProxy(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(
targetObject.getClass().getClassLoader(),//目标对象类加载器
targetObject.getClass().getInterfaces(),//目标对象实现的接口
this);
}
观察者模式
指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。
例如就是:微信公众号,或者是QQ微信群聊
观察者模式优点
降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
目标与观察者之间建立了一套触发机制。
观察者模式缺点
目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
观察者模式的结构
观察者模式的主要角色如下
抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
消费者模式
记忆方式
子类和父类
“可见性”表示该属性对类外的元素是否可见,包括公有(Public)、私有(Private)、受保护(Protected)和朋友(Friendly)4 种,在类图中分别用符号+、-、#、~表示。
继承
实线表示继承,是is-a的关系,表示扩展,不虚,很结实
实现
虚线表示实现,虚线代表“虚”无实体
对于组合,聚合
聚合是整体和部分的关系,两者具有不同的生命周期
组合是具有同一生命周期,是整体的关系
依赖
依赖:虚线表示依赖关系:临时用一下,若即若离,虚无缥缈,若有若无
表示一种使用关系,一个类需要借助另一个类来实现功能
一般一个类将另一个类作为参数使用,或作为返回值
关联
实线表示关联关系:关系稳定,实打实的关系,“铁哥们”
表示一个类对象和另一个类对象有关联
通常一个类中有另一个类对象作为属性
类之间的关系
组合关系
UML 将事物之间的联系归纳为 6 种,并用对应的图形类表示。下面根据类与类之间的耦合度从弱到强排列。UML 中的类图有以下几种关系:依赖关系、关联关系、聚合关系、组合关系、泛化关系和实现关系。其中泛化和实现的耦合度相等,它们是最强的。
类的可见性
“可见性”表示该属性对类外的元素是否可见,包括公有(Public)、私有(Private)、受保护(Protected)和朋友(Friendly)4 种,在类图中分别用符号+、-、#、~表示。
练习的结构流程图
entity:被dao调用,实体类
dao:和数据库相关,对数据进行操作,被业务层调用
service:业务层,专门用来处理业务,依赖于dao
console:界面层,调用service