当前位置: 首页 > news >正文

做网站无需备案专业搜索引擎优化电话

做网站无需备案,专业搜索引擎优化电话,搜狗浏览器网页版入口,wordpress图片设置水印2019经典的设计模式有23种,但是常用的设计模式一般情况下不会到一半,我们就针对一些常用的设计模式进行一些详细的讲解和分析,方便大家更加容易理解和使用设计模式。 1-为什么要使用单例 单例设计模式(Singleton Design Pattern&…

       经典的设计模式有23种,但是常用的设计模式一般情况下不会到一半,我们就针对一些常用的设计模式进行一些详细的讲解和分析,方便大家更加容易理解和使用设计模式。

1-为什么要使用单例

         单例设计模式(Singleton Design Pattern)理解起来非常简单。一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。

       从业务概念上,有些数据在系统中只应该保存一份,就比较适合设计为单例类。比如,系统的配置信息类。除此之外,我们还可以使用单例解决资源访问冲突的问题。在实际项目开发过程中,比如我们在单体项目中【这里先考虑单体】中我们需要一个类专门生成id,如果有多个实例,会产生重复的id,这种情况是我们不想看到的也是不能发生的,这样的情况我们必须采用单例模式。

2-如何实现一个单例

      实现单例的核心要点:
      1-构造函数需要是private访问权限的,这样才能避免外部通过new创建实例;
      2-考虑对象创建时的线程安全问题;
      3-考虑是否支持延迟加载;
      4-考虑getInstance()性能是否高(是否加锁)

2.1-饿汉式

      饿汉式的实现方式比较简单。在类加载的时候,instance静态实例就已经创建并初始化好了,所以,instance实例的创建过程是线程安全的。不过,这样的实现方式不支持延迟加载(在真正用到IdGenerator的时候,再创建实例)。具体的代码实现如下所示:

public class IdGenerator {private AtomicLong id = new AtomicLong(0);private static final IdGenerator instance = new IdGenerator();private IdGenerator() {}public static IdGenerator getInstance() {return instance;}public long getId() {return id.incrementAndGet();}
}

观点讨论:

       观点1:有人觉得这种实现方式不好,因为不支持延迟加载,如果实例占用资源多(比如占用内存多)或初始化耗时长(比如需要加载各种配置文件),提前初始化实例是一种浪费资源的行为。最好的方法应该在用到的时候再去初始化。

       观点2:如果初始化耗时长,那我们最好不要等到真正要用它的时候,才去执行这个耗时长的初始化过程,这会影响到系统的性能(比如,在响应客户端接口请求的时候,做这个初始化操作,会导致此请求的响应时间变长,甚至超时)。采用饿汉式实现方式,将耗时的初始化操作,提前到程序启动的时候完成,这样就能避免在程序运行的时候,再去初始化导致的性能问题。如果实例占用资源多,按照fail-fast的设计原则(有问题及早暴露),那我们也希望在程序启动时就将这个实例初始化好。如果资源不够,就会在程序启动的时候触发报错(比如Java中的 PermGen Space OOM),我们可以立即去修复。这样也能避免在程序运行一段时间后,突然因为初始化这个实例占用资源过多,导致系统崩溃,影响系统的可用性。

2.2-懒汉式

懒汉式相对于饿汉式的优势是支持延迟加载。

public class IdGenerator {private AtomicLong id = new AtomicLong(0);private static IdGenerator instance;private IdGenerator() {}public static synchronized IdGenerator getInstance() {if (instance == null) {instance = new IdGenerator();}return instance;}public long getId() {return id.incrementAndGet();}
}

       分析:我们给getInstance()这个方法加了一把大锁(synchronzed),导致这个函数的并发度很低。量化一下的话,并发度是1,也就相当于串行操作了。而这个函数是在单例使用期间,一直会被调用。如果这个单例类偶尔会被用到,那这种实现方式还可以接受。但是,如果频繁地用到,那频繁加锁、释放锁及并发度低等问题,会导致性能瓶颈,这种实现方式就不可取了。

2.3-双重检测

       饿汉式不支持延迟加载,懒汉式有性能问题,不支持高并发。那我们再来看一种既支持延迟加载、又支持高并发的单例实现方式,也就是双重检测实现方式。在这种实现方式中,只要instance被创建之后,即便再调用getInstance()函数也不会再进入到加锁逻辑中了。所以,这种实现方式解决了懒汉式并发度低的问题。 注意:添加volatile关键字,保证instance = new IdGenerator(); 完全执行完成。

public class IdGenerator {private AtomicLong id = new AtomicLong(0);private static volatile IdGenerator instance;private IdGenerator() {}public static IdGenerator getInstance() {if (instance == null) {synchronized(IdGenerator.class) { // 此处为类级别的锁if (instance == null) {instance = new IdGenerator();}}}return instance;}public long getId() {return id.incrementAndGet();}
}

2.4-静态内部类

       我们再来看一种比双重检测更加简单的实现方法,那就是利用Java的静态内部类。它有点类似饿汉式,但又能做到了延迟加载。

public class IdGenerator {private AtomicLong id = new AtomicLong(0);private IdGenerator() {}private static class SingletonHolder{private static final IdGenerator instance = new IdGenerator();}public static IdGenerator getInstance() {return SingletonHolder.instance;}public long getId() {return id.incrementAndGet();}
}

       SingletonHolder 是一个静态内部类,当外部类IdGenerator被加载的时候,并不会创建SingletonHolder实例对象。只有当调用getInstance()方法时,SingletonHolder才会被加载,这个时候才会创建instance。insance的唯一性、创建过程的线程安全性,都由JVM来保证。所以,这种实现方法既保证了线程安全,又能做到延迟加载。

2.5-枚举

       基于枚举类型的单例实现。这种实现方式通过Java枚举类型本身的特性,保证了实例创建的线程安全性和实例的唯一性。

public enum IdGenerator {INSTANCE;private AtomicLong id = new AtomicLong(0);public long getId() { return id.incrementAndGet();}
}

3-单例存在的问题

       大部分情况下,我们在项目中使用单例,都是用它来表示一些全局唯一类,比如配置信息类、连接池类、ID生成器类。单例模式书写简洁、使用方便,在代码中,我们不需要创建对象,直接通过类似IdGenerator.getInstance().getId()这样的方法来调用就可以了。但是,这种使用方法有点类似硬编码(hard code),会带来诸多问题。

3.1-单例对OOP特性的支持不友好

       OOP的四大特性是封装、抽象、继承、多态。单例这种设计模式对于其中的抽象、继承、多态都支持得不好。

       比如:订单业务,我们生成订单id 代码 long id = IdGenerator.getInstance().getId();用户业务我们生成用户id  long id = IdGenerator.getInstance().getId();

       IdGenerator的使用方式违背了基于接口而非实现的设计原则,也就违背了广义上理解的OOP的抽象特性。如果未来某一天,我们希望针对不同的业务采用不同的ID生成算法。比如,订单ID和用户ID采用不同的ID生成器来生成。为了应对这个需求变化,我们需要修改所有用到IdGenerator类的地方,这样代码的改动就会比较大。

3.2-单例会隐藏类之间的依赖关系

        单例类不需要显示创建、不需要依赖参数传递,在函数中直接调用就可以了。如果代码比较复杂,这种调用关系就会非常隐蔽。在阅读代码的时候,我们就需要仔细查看每个函数的代码实现,才能知道这个类到底依赖了哪些单例类。

3.3-单例对代码的扩展性不友好

       单例类只能有一个对象实例。如果未来某一天,我们需要在代码中创建两个实例或多个实例,那就要对代码有比较大的改动。

3.4-单例对代码的可测试性不友好

       单例模式的使用会影响到代码的可测试性。如果单例类依赖比较重的外部资源,比如DB,我们在写单元测试的时候,希望能通过mock的方式将它替换掉。而单例类这种硬编码式的使用方式,导致无法实现mock替换。 

3.5-单例不支持有参数的构造函数

      单例不支持有参数的构造函数,比如我们创建一个连接池的单例对象,我们没法通过参数来指定连接池的大小。怎么解决呢?

public class Config {public static final int PARAM_A = 123;public static final int PARAM_B = 245;
}public class Singleton {private static Singleton instance = null;private final int paramA;private final int paramB;private Singleton() {this.paramA = Config.PARAM_A;this.paramB = Config.PARAM_B;}public synchronized static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

4-单例有什么替代解决方案

       如果要完全解决这些问题,我们可能要从根上,寻找其他方式来实现全局唯一类了。比如,通过工厂模式、IOC容器(比如Spring IOC容器)来保证,由过程序员自己来保证(自己在编写代码的时候自己保证不要创建两个类对象)。

5-小结

       有人把单例当作反模式,主张杜绝在项目中使用。我个人觉得这有点极端。模式没有对错,关键看你怎么用。如果单例类并没有后续扩展的需求,并且不依赖外部系统,那设计成单例类就没有太大问题。对于一些全局的类,我们在其他地方new的话,还要在类之间传来传去,不如直接做成单例类,使用起来简洁方便。

http://www.dinnco.com/news/46753.html

相关文章:

  • 算命购物网站建设一周热点新闻
  • 网站后台页面模板下载西安seo网站推广优化
  • 乐陵德州seo公司宣城网站seo
  • 湖南专业做网站公司有哪些最近一周的新闻热点事件
  • 疑问句做网站标题百度爱采购竞价
  • 建设旅游网站建议广州线下教学
  • 男女做受网站中国网络推广网站排名
  • 赤峰市做网站多少钱百度不收录网站
  • 深圳住房和建设部网站网推是什么
  • 上海网站建设设计制作百度网盘官网登录入口
  • 如何做网站链接分析女孩子做运营是不是压力很大
  • 杭州企业网站设计好公司百度推广代理商与总公司的区别
  • 淘宝装修可以做代码的网站有哪些营销案例100例小故事
  • 电子商务网站功能aso优化是什么意思
  • 网站建设要做些什么问题自助搭建平台
  • 淘宝官网首页入口电脑版惠州seo代理
  • 黄山市建设工程造价管理站网站东莞网站设计
  • 东莞建设网雅园新村第20期名单公网站seo排名培训
  • 传奇网站架设方法百度图片识别
  • 做网站台式还是笔记本电商网站商品页的优化目标是什么
  • 网站建设新闻发布注意事项营销推广策划
  • 做游戏课程网站行业关键词查询
  • 西安网站建设l西安搜推宝网络2024免费网站推广大全
  • WordPress会员中心模板seo整站优化系统
  • 学做快餐在哪个网站p2p万能搜索引擎
  • asp网站建设广州seo实战培训
  • 博物馆建设网站网络营销好学吗
  • 上海哪家做网站好成都网站快速排名软件
  • 利用wps做网站竞价恶意点击器
  • 企业在网站建设上的不足今日疫情最新消息