Java进阶篇设计模式之一 ----- 单例模式
前言
在刚学编程没多久就听说过设计模式的大名,不过由于当时还是个彻彻底底的菜鸟,并没有去触碰。直到在开始工作中对简单的业务代码较为熟悉之后,才正式的接触设计模式。当时最早接触的设计模式是工厂模式,不过本文讲的是单例模式,这里就留着下篇文章中在讲解。至于为什么先讲解单例模式? 那是因为单例模式是设计模式中最简单的... 。凡事总有个先后顺序,所以就先易后难了。好了,废话不多说了,开始进入正片。
设计模式简介
说明:这里说了的简介就是真的 “简介”。
什么是设计模式
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。
为什么使用设计模式
使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。
设计模式类型
设计模式有23种类型。按照主要分类可以分为三大类:
一、创建型模式
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
- 单例模式
- 工厂模式
- 抽象工厂模式
- 建造者模式
- 原型模式
二、结构型模式
这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
- 适配器模式
- 桥接模式
- 过滤器模式
- 组合模式
- 装饰器模式
- 外观模式
- 享元模式
- 代理模式
三、行为型模式
这些设计模式特别关注对象之间的通信。
- 责任链模式
- 命令模式
- 解释器模式
- 迭代器模式
- 中介者模式
- 备忘录模式
- 观察者模式
- 状态模式
- 空对象模式
- 策略模式
- 模板模式
- 访问者模式
设计模式的原则
设计模式的六大原则
- 开闭原则:对扩展开放,对修改关闭。
- 里氏代换原则:对开闭原则的补充。任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。
- 依赖倒转原则:针对接口编程,依赖于抽象而不依赖于具体。
- 接口隔离原则:尽量使用多个隔离的接口,为了降低类之间的耦合度。
- 迪米特法则:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
- 合成复用原则:尽量使用合成/聚合的方式,而不是使用继承。
单例模式
什么是单例模式
保证一个系统中的某个类只有一个实例而且该实例易于外界访问。例如Windows界面的任务管理器就可以看做是一个单例。
单例模式的使用场景
在程序中比较常用的是数据库连接池、线程池、日志对象等等。
单例模式使用
最早我们在学习单例模式的时候,基本都会接触这两种模式:饿汉式和饱汉式(懒汉式)。
那我们先来看看这两个模式的实现。
饿汉式
定义一个私有的构造方法,并将自身的实例对象设置为一个私有属性,并加上static和final修饰符,然后通过公共的静态方法调用返回实例。
class SingletonTest1 {
private SingletonTest1() {
}
private static final SingletonTest1 instance = new SingletonTest1();
public static SingletonTest1 getInstance() {
return instance;
}
}
饱汉式
定义一个私有的构造方法,定义一个该类静态私有的变量,然后定义一个公共的静态方法,对该类的值进行空判断,不为空直接返回,否则重新构建一个。
class SingletonTest2 {
private SingletonTest2() {
}
private static SingletonTest2 instance;
public static SingletonTest2 getInstance() {
if (instance == null) {
instance = new SingletonTest2();
}
return instance;
}
}
简单的介绍了这两种的模式,然后我们再来看看这两种模式的优缺点吧。
饿汉式
- 优点:写起来很简单,并且不会因为不加synchronized关键字而造成的线程不安全问题。
- 缺点:当该类被加载的时候,会初始化该实例和静态变量并被创建并分配内存空间,并且会一直占用内存。
饱汉式
- 优点:写起来很简单,在第一次调用的时候才会初始化,节省了内存。
- 缺点:线程不安全,多个线程调用可能会出现多个实例。
- 总结:书写简单,线程不安全,效率还行。
虽然 饱汉式可以通过加上synchronized关键字保证线程安全。但是效率方法来说还不说是最优。
这里在介绍下个人认为在JDK1.5之前最优的两种写法,一种是静态内部类,另一种是双重锁检查。
静态内部类
定义一个私有的构造方法,定义一个该类私有静态的内部类,然后在内部类中定义一个该类的静态变量,然后通过公共的final修饰的静态方法调用返回实例。
class SingletonTest4 {
private SingletonTest4(){
}
private static class SingletonTest5{
private static SingletonTest4 instance = new SingletonTest4();
}
public static final SingletonTest4 getInstance(){
return SingletonTest5.instance;
}
}
因为该类的内部类是私有的,除了对外公布的公共静态方法getInstance(),是无法访问的。因为它是延迟加载,所以读取读取实例的时候不会进行同步,几乎没有性能的缺陷,而且还是线程安全的,并且不依赖JDK的版本。
双重锁检查
定义一个私有构造方法,通过volatile定义静态私有变量,保证了该变量的可见性,然后定义一个共有的静态方法,第一次对该对象实例化时与否判断,不为空直接返回,提升效率;然后使用synchronized 进行同步代码块,防止对象未初始化时,在多线程访问该对象在第一次创建后,再次重复的被创建;然后第二次对该对象实例化时与否判断,如果未初始化,则初始化,否则直接返回该实例。
class SingletonTest6 {
private SingletonTest6() {
}
private static volatile SingletonTest6 instance;
public static SingletonTest6 getIstance() {
if (instance == null) {
synchronized (SingletonTest6.class) {
if (instance == null) {
instance = new SingletonTest6();
}
}
}
return instance;
}
}
这种模式在很长的一段时间内可以说是最优的了,内存占用低,效率高,线程安全,多线程操作原子性。但是有个缺点就是书写麻烦,对新手不太友好。
JDK1.5之后出现了枚举,并且完美支持单例模式,并且线程安全、效率高!但是这些不是最重要的,最重要的是书写超级简单!究竟有多简单,看下面的示例应该就可以了解一下了。。。
枚举单例
enum SingletonTest7{
INSTANCE;
}
对的,你没看错,就这点代码,其它不需要了。。。
枚举需要在JDK1.5之后的版本,它无偿提供序列化机制,绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候。这种方法也被Effective Java作者Josh Bloch 所提倡。
总结
单例模式的几种使用就到这了,那么我们来总结下使用单例模式需要注意什么(不包括枚举)。
- 构造方法私有化(private);
- 定义一个私有(private)静态(static)实例化对象;
- 对外提供一个公共(public)静态(static)的方法得到该实例;
原创不易,如果感觉不错,希望给个推荐!您的支持是我写作的最大动力!
版权声明:
作者:虚无境
博客园出处:http://www.cnblogs.com/xuwujing
CSDN出处:http://blog.csdn.net/qazwsxpcm
个人博客出处:http://www.panchengming.com
Java进阶篇设计模式之一 ----- 单例模式的更多相关文章
- Java进阶篇 设计模式之十四 ----- 总结篇
前言 本篇是讲述之前学习设计模式的一个总结篇,其目的是为了对这些设计模式的进行一个提炼总结,能够通过查看看此篇就可以理解一些设计模式的核心思想. 设计模式简介 什么是设计模式 设计模式是一套被反复使用 ...
- Java进阶篇设计模式之七 ----- 享元模式和代理模式
前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...
- Java进阶篇设计模式之二 ----- 工厂模式
前言 在上一篇中我们学习了单例模式,介绍了单例模式创建的几种方法以及最优的方法.本篇则介绍设计模式中的工厂模式,主要分为简单工厂模式.工厂方法和抽象工厂模式. 简单工厂模式 简单工厂模式是属于创建型模 ...
- Java进阶篇设计模式之十三 ---- 观察者模式和空对象模式
前言 在上一篇中我们学习了行为型模式的备忘录模式(Memento Pattern)和状态模式(Memento Pattern).本篇则来学习下行为型模式的最后两个模式,观察者模式(Observer P ...
- Java进阶篇设计模式之十一 ---- 策略模式和模板方法模式
前言 在上一篇中我们学习了行为型模式的访问者模式(Visitor Pattern)和中介者模式(Mediator Pattern).本篇则来学习下行为型模式的两个模式,策略模式(Strategy Pa ...
- Java进阶篇设计模式之十 ---- 访问者模式和中介者模式
前言 在上一篇中我们学习了行为型模式的解释器模式(Interpreter Pattern)和迭代器模式(Iterator Pattern).本篇则来学习下行为型模式的两个模式,访问者模式(Visito ...
- Java进阶篇设计模式之九----- 解释器模式和迭代器模式
前言 在上一篇中我们学习了行为型模式的责任链模式(Chain of Responsibility Pattern)和命令模式(Command Pattern).本篇则来学习下行为型模式的两个模式, 解 ...
- Java进阶篇设计模式之八 ----- 责任链模式和命令模式
前言 在上一篇中我们学习了结构型模式的享元模式和代理模式.本篇则来学习下行为型模式的两个模式, 责任链模式(Chain of Responsibility Pattern)和命令模式(Command ...
- Java进阶篇设计模式之三 ----- 建造者模式和原型模式
前言 在上一篇中我们学习了工厂模式,介绍了简单工厂模式.工厂方法和抽象工厂模式.本篇则介绍设计模式中属于创建型模式的建造者模式和原型模式. 建造者模式 简介 建造者模式是属于创建型模式.建造者模式使用 ...
随机推荐
- XStream实现缓存
************************************************************************************ 系统实现缓存有多种方式,如re ...
- JUC中AQS简介
AQS,在java.util.concurrent.locks包中,AbstractQueuedSynchronizer这个类是并发包中的核心,了解其他类之前,需要先弄清楚AQS.在JUC的很多类中都 ...
- 新版知乎登录之post请求
前言 在上一篇文章中给大家讲解了requests发送post请求的几种方式,并分析了一些使用陷阱. 疑惑 在文章发表之后,有朋友给我留言说,知乎登录就没有使用提交Form表单(application/ ...
- Word2Vec总结
摘要: 1.算法概述 2.算法要点与推导 3.算法特性及优缺点 4.注意事项 5.实现和具体例子 6.适用场合 内容: 1.算法概述 Word2Vec是一个可以将语言中的字词转换为向量表达(Vecto ...
- IOT高性能服务器实现之路
市场动态 物联网市场在2018年第一季度/第二季度出现了意想不到的加速,并将使用的物联网设备总数提升至7B.这是IoT Analytics最新“ 物联网和短期展望状态 ”更新中的众多发现之一. 全面的 ...
- Spark学习之数据读取与保存总结(一)
一.动机 我们已经学了很多在 Spark 中对已分发的数据执行的操作.到目前为止,所展示的示例都是从本地集合或者普通文件中进行数据读取和保存的.但有时候,数据量可能大到无法放在一台机器中,这时就需要探 ...
- CTF丨2019互联网安全城市巡回赛·西安站,我们来了!
万物互联时代,网信事业发展突飞猛进,互联网悄然渗透到国民生活的每一个角落,伴随而来的网络安全威胁和风险也日渐突出.网络诈骗.钓鱼软件.勒索病毒等安全问题层出不穷,信息泄露等网络安全事件也频繁上演,给用 ...
- :Android网络编程--XML之解析方式:SAX
任何放置在资源(res)目录下的内容可以通过应用程序的R类访问,这是被Android编译过的,而任何放置在资产(assets)目录下的内容会保持它的原始文件格式,为了读取它们,必须使用AssetMan ...
- 视频当道的时代,这些珍藏的优质 Python 播客值得推荐
我国互联网的发展道路与欧美不同,在内容的形式上,我们似乎实现了跨越式的发展——早早进入了移动互联网时代,直播和短视频等形式的内容成为了潮流,而文字形式的博客(blog)与声音形式的播客(podcast ...
- RabbitMQ死信队列另类用法之复合死信
前言 在业务开发过程中,我们常常需要做一些定时任务,这些任务一般用来做监控或者清理任务,比如在订单的业务场景中,用户在创建订单后一段时间内,没有完成支付,系统将自动取消该订单,并将库存返回到商品中,又 ...