基本介绍
- 装饰模式:解决 类爆炸
<<设计模式>> 是经典的书,作者是 Erich Gamma、 Richard Helm、 Ralph
Johnson 和 John Vlissides Design(俗称 “四人组 GOF”)
分为三种类型,共23种
-
创建型模式: 单例模式、抽象工厂模式、原型模式、建造者模式、 工厂模式。
-
结构型模式:适配器模式、桥接模式、 装饰模式、组合模式、外观模式、享
元模式、 代理模式。 -
行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、 观察者
模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模
式、策略模式、职责链模式(责任链模式)。
单例
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类
只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
比如Hibernate的SessionFactory,它充当数据存储源的代理,并负责创建Session
对象。 SessionFactory并不是轻量级的,一般情况下,一个项目通常只需要一个
SessionFactory就够,这是就会使用到单例模式。
八种方式:
-
饿汉式(静态常量)
-
饿汉式(静态代码块)
-
懒汉式(线程不安全)
-
懒汉式(线程安全,同步方法)
-
懒汉式(线程安全,同步代码块)
-
双重检查
-
静态内部类
-
枚举
1. 饿汉式(静态常量) 推荐
步骤如下:
1) 构造器私有化 (防止 new )
2) 类的内部创建对象
3) 向外暴露一个静态的公共方法。 getInstance
4) 代码实现
//饿汉式(静态变量)
class Singleton {
//1. 构造器私有化, 外部能new
private Singleton() {
}
//2.本类内部创建对象实例
private final static Singleton instance = new Singleton();
//3. 提供一个公有的静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}
}
优缺点说明:
1) 优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同
步问题。
2) 缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始
至终从未使用过这个实例,则会造成内存的浪费
3) 这种方式基于classloder机制避免了多线程的同步问题,不过, instance在类装载
时就实例化,在单例模式中大多数都是调用getInstance方法, 但是导致类装载
的原因有很多种, 因此不能确定有其他的方式(或者其他的静态方法)导致类
装载,这时候初始化instance就没有达到lazy loading的效果
4) 结论:这种单例模式可用, 可能造成内存浪费
2. 饿汉式(静态代码块)
class Singleton {
//1. 构造器私有化, 外部能new
private Singleton() {
}
//2.本类内部创建对象实例
private static Singleton instance;
static { // 在静态代码块中,创建单例对象
instance = new Singleton();
}
//3. 提供一个公有的静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}
}
3. 懒汉式(线程不安全)
class Singleton {
private static Singleton instance;
private Singleton() {}
//提供一个静态的公有方法,当使用到该方法时,才去创建 instance
//即懒汉式
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
优缺点说明:
1) 起到了Lazy Loading的效果,但是只能在单线程下使用。
2) 如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及
往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以
在多线程环境下不可使用这种方式
3) 结论:在实际开发中,不要使用这种方式.
4. 懒汉式(线程安全,同步方法)
//提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
//即懒汉式
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
优缺点说明:
1) 解决了线程不安全问题
2) 效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行
同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,
直接return就行了。方法进行同步效率太低
3) 结论: 在实际开发中, 不推荐使用这种方式
5. (无用)懒汉式(线程安全,同步代码块)
- 线程安全都 解决不了
public static synchronized Singleton getInstance() {
if(instance == null) {
//两个线程 已经过来了,无意义
synchronized(Singleton.class){
instance = new Singleton();
}
}
return instance;
}
优缺点说明:
1) 这种方式,本意是想对第四种实现方式的改进,因为前面同步方法效率太低,
改为同步产生实例化的的代码块
2) 但是这种同步并不能起到线程同步的作用。跟第3种实现方式遇到的情形一
致,假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,
另一个线程也通过了这个判断语句,这时便会产生多个实例
3) 结论:在实际开发中, 不能使用这种方式
6. 双重检查 推荐
class Singleton {
private static volatile Singleton instance;
private Singleton() {}
//提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题
//同时保证了效率, 推荐使用
public static synchronized Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
优缺点说明:
1) Double-Check概念是多线程开发中常使用到的, 如代码中所示,我们进行了两
次if (singleton == null)检查,这样就可以保证线程安全了。
2) 这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),
直接return实例化对象,也避免的反复进行方法同步.
3) 线程安全;延迟加载;效率较高
4) 结论:在实际开发中,推荐使用这种单例设计模式
7. 静态内部类 推荐
-
主类 装载的时候,静态内部类,不会装载。懒加载
-
线程安全
// 静态内部类完成, 推荐使用 class Singleton { //构造器私有化 private Singleton() {} //写一个静态内部类,该类中有一个静态属性 Singleton private static class SingletonInstance { private static final Singleton INSTANCE = new Singleton(); } //提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE public static Singleton getInstance() { return SingletonInstance.INSTANCE; } }
优缺点说明:
1) 这种方式采用了类装载的机制来保证初始化实例时只有一个线程。
2) 静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化
时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的
实例化。
3) 类的静态属性只会在第一次加载类的时候初始化,所以在这里, JVM帮助我们
保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
4) 优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
5) 结论:推荐使用.
8. 枚举 推荐
public class SingletonTest08 {
public static void main(String[] args) {
Singleton instance = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance == instance2);
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
instance.sayOK();
}
}
//使用枚举,可以实现单例, 推荐
enum Singleton {
INSTANCE; //属性
public void sayOK() {
System.out.println("ok~");
}
}
优缺点说明:
1) 这借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而
且还能防止反序列化重新创建新的对象。
2) 这种方式是Effective Java作者Josh Bloch 提倡的方式
3) 结论:推荐使用
其他的方法:
1. 全局静态变量(不算)
public class Singleton_00 {
//jvm初始化的过程中,实例化属性。保存全局的对象
public static Map<String, String> cache = new ConcurrentHashMap<String, String>();
}
2. CAS
public class Singleton_06 {
//定义 atomic
private static final AtomicReference<Singleton_06> INSTANCE = new AtomicReference<Singleton_06>();
//private static Singleton_06 instance;//这个变量没用,最好注释
private Singleton_06() {
}
//final 可以省略
public static final Singleton_06 getInstance() {
//死循环
for (; ; ) {
//获得 这个对象。用静态的也行吧
Singleton_06 instance = INSTANCE.get();
//如果不为null,就返回
if (null != instance) return instance;
//为null,就创建
//无锁 算法,CPU指令集操作,只有一步 原子操作
INSTANCE.compareAndSet(null, new Singleton_06());
//然后 返回
return INSTANCE.get();
}
}
}
Reference
n. 提及,谈到;参考,查阅;(引自书或诗歌的)引言,引文;引文的作者,参考书目;(帮助或意见的)征求,征询; (为方便查询所用的)标记,编号;推荐信,介绍信;介绍人,推荐人
adj. 参考的,用于查阅的;文献索引的,参照的
v. 列出……的参考书目;提及,提到;引用,参照(某书或某作者)
JDK 使用单例
我们JDK中, java.lang.Runtime就是经典的单例模式(饿汉式)
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {}
}
单例模式注意事项和细节说明
-
单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需
要频繁创建销毁的对象,使用单例模式可以提高系统性能 -
当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使
用new -
单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或
耗费资源过多(即:重量级对象), 但又经常用到的对象、工具类对象、频繁访问数
据库或文件的对象(比如数据源、 session工厂等)
Runtime
打印内存 和 垃圾回收
Runtime类描述了虚拟机一些信息。
该类采用了单例设计模式,
可以通过静态方法 getRuntime()获取Runtime类实例。
Runtime runtime = Runtime.getRuntime();
System.out.println("total memory:"+runtime.totalMemory()/(1024*1024) + "M");
System.out.println("max memory:" + runtime.maxMemory()/(1024*1024) + "M");
System.out.println("free memory:" + runtime.freeMemory()/(1024*1024) + "M");
Runtime类提供gc()方法,用于释放Java虚拟机的一些无用空间。
gc是garbage collection的缩写,就是垃圾回收的意思。
runtime.gc();
调用系统的程序
Runtime类可以调用本机的一些可执行程序,并且创建进程。exec(String cmd)方法可以打开一个可执行程序,下面代码演示了打开windows记事本程序并5秒后关闭。
Process process = runtime.exec("notepad");
Thread.sleep(1000*5);
process.destroy();
1. UML
1) UML——Unified modeling language UML
(统一建模语言),是一种用于软件系统
分析和设计的语言工具,它用于帮助软
件开发人员进行思考和记录思路的结果
2) UML本身是一套符号的规定,就像数学
符号和化学符号一样,这些符号用于描
述软件模型中的各个元素和他们之间的
关系,比如类、接口、
依赖、-----> 虚线
关联、_______ 实线
继承(泛化)、————▷ 实线 ___▷
实现、------▷ 虚线
聚合、——————◇ 实线 ____◇
组合、——————♦ 实线 ____♦
3) 使用UML来建模,常用的工具有 Rational
Rose , 也可以使用一些插件来建模
rational
英 /ˈræʃnəl/ 美 /ˈræʃ(ə)nəl/ 全球(英国)
adj. (想法、决定等)合理的,基于理性的;(人)理性的,理智的;富有理性的;(数)有理的,有理数的
n. 有理数
为了画UML图,在Eclipse安装AmaterasUML
可以画:
activity diagram 活动图
class diagram 类图
sequence diagram 时序图
usecase diagram 用例图
图形表示
-
依赖(使用)
- Dependency
- 方法的参数 (a:A)
- 依赖,箭头,剑身是虚线
- ------------>
- 构造传递也是 方法,也是依赖。
-
关联
- association
- 一条线,一对一,一对n
- ————
-
泛化(继承)
- Generalization
- 泛化,就是 空心的三角箭头,实心的线
- ————▷
-
实现
- implementation 和 realization
- 空心的三角形,虚线
- --------------▷
-
聚合
- Aggregation
- 定义属性 a:A,
- 使用 setA(a:A) 方法赋值
- 当前类X,聚合了 A类
- 依赖方为 菱形(空心),实线方 为 被依赖,如上例的A
- ————◇
- 可分离
-
组合
- 组合 B类里,new A();
- 耦合性 比聚合强
- composite
- 依赖方为 菱形(实心)
- ———♦
- 不可分离
- 组合 B类里,new A();
所属单词
1. Dependency
2. association
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
n. 协会,社团,联盟;交往,联合;联系,因果关系;联想
复数 associations
3. Gen era li zation
Generalization
英 /ˌdʒenrəlaɪˈzeɪʃn/ 美 /ˌdʒenrələˈzeɪʃn/ 全球(美国)
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
n. (依据不足的)概括,泛论(=generalisation)
4. implementation 和 realization
realization
英 /ˌriːəlaɪˈzeɪʃn; ˌrɪəlaɪˈzeɪʃn/ 美 /ˌriːələˈzeɪʃn/ 全球(英国)
简明 牛津 新牛津 韦氏 例句 百科
n. 认识,领悟;(目标等的)实现;变现,变卖;兑谱,改编;(语言特征的)体现;货物销售;发声,(戏剧)演出,设计成果
5. Aggregation
英 /ˌæɡrɪˈɡeɪʃn/ 美 /ˌæɡrɪˈɡeɪʃn/ 全球(美国)
简明 韦氏 柯林斯 例句 百科
n. 聚集,聚合;(互联网)相关内容项的集合;聚集体,集合体
6. composition
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
n. 成分构成,成分;(音乐、艺术、诗歌的)作品;创作,作曲;构图;作文
复数 compositions
composite
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
adj. 合成的,复合的;(火车车厢)综合的;菊科的;(柱式)混合的
n. 合成物,复合材料;罪犯画像;综合提案;菊科植物;混合柱式
v. 合成(图片)
terminate
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
v. (使)结束,(使)终止;到达终点站;终止妊娠,人工流产;<美>解雇;<美>谋杀(某人);在……结尾,以……收尾
relation
英 /rɪˈleɪʃn/ 美 /rɪˈleɪʃn/
n. (人或物间的)联系;(国家、公司、组织等之间的)(正式)关系;<正式> 性关系;亲戚,亲属;讲述,叙述
dispatch
英 /dɪˈspætʃ/ 美 /dɪˈspætʃ/
v. 派遣;发送;迅速处理,迅速办妥;杀死,处决
n. 派遣,发送;公文,急件;报道,电讯;杀死,除掉
UML图 划分
1) 用例图(use case)
2) 静态结构图: 类图、对象图、包图、组件图、部署图
3) 动态行为图:交互图(时序图与协作图)、状态图、活动图
说明:
1) 类图是描述类与类之间的关系的,是UML图中最核心的
极简案例
public class Person{ //代码形式->类图
private Integer id;
private String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
}
com.xxx.Person
id: Integer
name: String
setName(name:String): void
getName(): String
依赖 ---->
- A 用到 B,称: A 依赖于 B
- 箭头的方向指向B
类图—依赖关系(Dependence)
只要是在类中用到了对方, 那么他们之间就存在依赖关系。如果没有对方,连编
绎都通过不了。
全局/局部变量,形参,返回值
public class PersonServiceBean {
//全局变量。用 聚合也没错
private PersonDao personDao;//类
//参数
public void save(Person person) {
}
//返回值
public IDCard getIDCard(Integer personid) {
}
public void modify() {
//违反了 迪米特。如果这叫依赖,那 依赖包含:组合
Department department = new Department();
}
}
public class PersonDao {
}
public class IDCard {
}
public class Person {
}
public class Department {
//同上 是组合关系
}
- 去掉+号
PersonServiceBean
+ personDao: PersonDao //用 聚合也没错。聚合的话,菱形在 主类
+ save(person:Person): void
+ getIDCard(personid:Integer): IDCard
+ modify(): void
小结
类中用到了对方
1) 如果是类的成员属性
2) 如果是方法的返回类型
3) 是方法接收的参数类型
4) 方法中使用到(局部变量)
泛化(继承)—▷
类图—泛化关系(generalization)
泛化关系实际上就是继承关系,他是依赖关系的特例
public abstract class DaoSupport{
public void save(Object entity){
}
public void delete(Object id){
}
}//箭头的头指向
//箭头的尾巴
public class PersonServiceBean extends Daosupport{
}
小结:
1) 泛化关系实际上就是继承关系
2) 如果A类继承了B类,我们就说A和B存在泛化关系
实现----▷
类图—实现关系(Implementation)
实现关系实际上就是A类实现B接口, 他是依赖关系的特例
public interface PersonService {
public void delete(Interger id);
}//箭头
//箭 尾巴
public class PersonServiceBean implements PersonService {
public void delete(Interger id){}
}
关联 —
类图—关联关系(Association)
关联关系实际上就是类与类之间的联系,他是依赖关系的特例
关联具有导航性:即双向关系或单向关系
关系具有多重性:
- 如“1”(表示有且仅有一个),
- “0…”(表示0个或者多个),
- “0, 1”(表示0个或者一个),
- “n…m”(表示n到 m个都可以),
- “m…*”(表示至少m
个)。
单向一对一关系
public class Person {
// Person —> IDCard
private IDCard card;
}
public class IDCard{}
双向一对一关系 1————1
public class Person {
private IDCard card;
}
public class IDCard{
private Person person
}
聚合—◇
类图—聚合关系(Aggregation)
聚合关系(Aggregation)表示的是
-
整体和部分的关系, 整体与部分可以分开。
-
聚合关系是 关联关系的特例,所以他具有关联的导航性与多重性。
-
如:一台电脑由键盘(keyboard)、显示器(monitor),鼠标等组成;组成电脑的各个
- 配件是可以从电脑上分离出来的, 使用带空心菱形的实线来表示:
- 不可以分开,是组合的关系。
//空心菱形,指向整体的 部分
public class Computer {
private Mouse mouse; //鼠标可以和computer分离
private Moniter moniter;//显示器可以和Computer分离
public void setMouse(Mouse mouse) {
this.mouse = mouse;
}
public void setMoniter(Moniter moniter) {
this.moniter = moniter;
}
}
组合—♦
也是关联的特例
如果我们人Mouse,Monitor和Computer是不可分离的,则升级为组合关系
- 共生共灭
//主类,对着 黑心的菱形
public class Computer {
private Mouse mouse = new Mouse(); //鼠标可以和computer不能分离
private Moniter moniter = new Moniter();//显示器可以和Computer不能分离
public void setMouse(Mouse mouse) {
this.mouse = mouse;
}
public void setMoniter(Moniter moniter) {
this.moniter = moniter;
}
}
Composition
组合关系:也是整体与部分的关系,但是整体与部分不可以分开。
再看一个案例:在程序中我们定义实体: Person与IDCard、 Head,
- 那么 Head 和 Person 就是 组合,
- IDCard 和 Person 就是聚合。
- 但是如果在程序中Person实体中定义了对IDCard进行级联删除,
- 删除所有的人,班级也删除。就是:组合关系。
- 即删除Person时连同IDCard一起删除, 那么IDCard 和 Person 就是组合了.
- 但是如果在程序中Person实体中定义了对IDCard进行级联删除,
public class Person{
private IDCard card;
//头,不能分开
private Head head = new Head();
}
public class IDCard{}
public class Head{}