1.单例

创建一个单例

//懒汉模式 + synchronized同步锁 + double-check

public final class Singleton {private volatile static Singleton instance= null;//不实例化public List<String> list = null;//list属性private Singleton(){list = new ArrayList<String>();}//构造函数public static Singleton getInstance(){//加同步锁,通过该函数向整个系统提供实例if(null == instance){//第一次判断,当instance为null时,则实例化对象,否则直接返回对象synchronized (Singleton.class){//同步锁if(null == instance){//第二次判断instance = new Singleton();//实例化对象}} }return instance;//返回已存在的对象}
}

在多线程场景下,JVM 会保证只有一个线程能执行该类的 clinit(static 修饰的成员变量)方法,其它线程将会被阻塞等待。这种方式可以保证内存的可见性、顺序性以及原子性。

//懒汉模式 内部类实现

public final class Singleton {public List<String> list = null;// list属性private Singleton() {//构造函数list = new ArrayList<String>();}// 内部类实现public static class InnerSingleton {private static Singleton instance=new Singleton();//自行创建实例}public static Singleton getInstance() {return InnerSingleton.instance;// 返回内部类中的静态变量}
}

为什么单例:

我们将 Logger 设计成一个单例类,程序中只允许创建一个 Logger 对象,所有的线程共享使用的这一个 Logger 对象,共享一个 FileWriter 对象,而 FileWriter 本身是对象级别线程安全的,也就避免了多线程情况下写日志会互相覆盖的问题。

有些数据在系统中只应保存一份,那就比较适合设计为单例类。比如,配置信息类,连接池类、ID 生成器类

通过枚举实现单例:

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

单例类中对象的唯一性的作用范围是“进程唯一”的。
实现线程唯一:
我们通过一个 HashMap 来存储对象,其中 key 是线程 ID,value 是对象。这样我们就可以做到,不同的线程对应不同的对象,同一个线程只能对应一个对象。
实现集群唯一:
我们需要把这个单例对象序列化并存储到外部共享存储区(比如文件)。进程在使用这个单例对象的时候,需要先从外部共享存储区中将它读取到内存,并反序列化成对象,然后再使用,使用完成之后还需要再存储回外部共享存储区。为了保证任何时刻在进程间都只有一份对象存在,一个进程在获取到对象之后,需要对对象加锁,避免其他进程再将其获取。在进程使用完这个对象之后,需要显式地将对象从内存中删除,并且释放对对象的加锁。

原型模式与享元模式

原型模式和享元模式,前者是在创建多个实例时,对创建过程的性能进行调优;后者是用减少创建实例的方式,来调优系统性能。

原型模式(使用 clone 方法复制一个对象)
1.实现 Cloneable 接口;2.重写 Object 类中的 clone 方法 3 在重写的 clone 方法中调用 super.clone():默认情况下,类不具备复制对象的能力,需要调用 super.clone() 来实现。

深拷贝和浅拷贝
除了基本类型,对于对象的引用以及 List 等类型的成员属性,则只能复制这些对象的引用了。所以简单调用 super.clone() 这种克隆对象方式,就是一种浅拷贝。

深拷贝就是基于浅拷贝来递归实现具体的每个对象

使用场景:如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同)
实际上,创建对象包含的申请内存、给成员变量赋值这一过程,本身并不会花费太多时间,但是,如果对象中的数据需要经过复杂的计算才能得到(比如排序、计算哈希值),或者需要从 RPC、网络、数据库、文件系统等非常慢速的 IO 中读取,这种情况下,我们就可以利用原型模式。

那如何实现深拷贝:
第一种方法:递归拷贝对象、对象的引用对象以及引用对象的引用对象……直到要拷贝的对象只包含基本数据类型数据,没有引用对象为止。
第二种方法:先将对象序列化,然后再反序列化成新的对象。

享元模式

//抽象享元类

interface Flyweight {//对外状态对象void operation(String name);//对内对象String getType();
}

//具体享元类

class ConcreteFlyweight implements Flyweight {private String type;public ConcreteFlyweight(String type) {this.type = type;}@Overridepublic void operation(String name) {System.out.printf("[类型(内在状态)] - [%s] - [名字(外在状态)] - [%s]\n", type, name);}@Overridepublic String getType() {return type;}
}

//享元工厂类

class FlyweightFactory {private static final Map<String, Flyweight> FLYWEIGHT_MAP = new HashMap<>();//享元池,用来存储享元对象public static Flyweight getFlyweight(String type) {if (FLYWEIGHT_MAP.containsKey(type)) {//如果在享元池中存在对象,则直接获取return FLYWEIGHT_MAP.get(type);} else {//在响应池不存在,则新创建对象,并放入到享元池ConcreteFlyweight flyweight = new ConcreteFlyweight(type);FLYWEIGHT_MAP.put(type, flyweight);return flyweight;}}
}
public class Client {public static void main(String[] args) {Flyweight fw0 = FlyweightFactory.getFlyweight("a");Flyweight fw1 = FlyweightFactory.getFlyweight("b");Flyweight fw2 = FlyweightFactory.getFlyweight("a");Flyweight fw3 = FlyweightFactory.getFlyweight("b");fw1.operation("abc");System.out.printf("[结果(对象对比)] - [%s]\n", fw0 == fw2);System.out.printf("[结果(内在状态)] - [%s]\n", fw1.getType());}
}

如果对象已经存在于享元池中,则不会再创建该对象了,而是共用享元池中内部数据一致的对象。这样就减少了对象的创建,同时也节省了同样内部数据的对象所占用的内存空间。例如 Java 的 String 字符串,在一些字符串常量中,会共享常量池中字符串对象,从而减少重复创建相同值对象,占用内存空间。

生产者消费者模式

生产者与消费者是通过一个中间容器来解决强耦合关系,并以此来实现不同的生产与消费速度,从而达到缓冲的效果。

1.Object 的 wait/notify/notifyAll 实现生产者消费者
基于 Object 的 wait/notify/notifyAll 与对象监视器(Monitor)实现线程间的等待和通知
2.Lock 中 Condition 的 await/signal/signalAll 实现生产者消费者
显示锁 ReentrantLock 或 ReentrantReadWriteLock 都是基于 AQS 实现的,AQS 中存在一个同步队列(CLH 队列),当一个线程没有获取到锁时就会进入到同步队列中进行阻塞,如果被唤醒后获取到锁,则移除同步队列。

生产消费案例

  private LinkedList<String> product = new LinkedList<String>();private AtomicInteger inventory = new AtomicInteger(0);//实时库存private int maxInventory = 10; // 最大库存private Lock consumerLock = new ReentrantLock();// 资源锁private Lock productLock = new ReentrantLock();// 资源锁private Condition notEmptyCondition = consumerLock.newCondition();// 库存满和空条件private Condition notFullCondition = productLock.newCondition();// 库存满和空条件/*** 新增商品库存* @param e*/public void produce(String e) {productLock.lock();try {while (inventory.get() == maxInventory) {notFullCondition.await();}product.add(e);System.out.println("放入一个商品库存,总库存为:" + inventory.incrementAndGet());if(inventory.get()<maxInventory) {notFullCondition.signalAll();}} catch (Exception ex) {ex.printStackTrace();} finally {productLock.unlock();}if(inventory.get()>0) {try {consumerLock.lockInterruptibly();notEmptyCondition.signalAll();} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}finally {consumerLock.unlock();}}}/*** 消费商品* @return*/public String consume() {String result = null;consumerLock.lock();try {while (inventory.get() == 0) {notEmptyCondition.await();}result = product.removeLast();System.out.println("消费一个商品,总库存为:" + inventory.decrementAndGet());if(inventory.get()>0) {notEmptyCondition.signalAll();}} catch (Exception e) {e.printStackTrace();} finally {consumerLock.unlock();}if(inventory.get()<maxInventory) {try {productLock.lockInterruptibly();notFullCondition.signalAll();} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}finally {productLock.unlock();}}return result;}/*** 生产者* @author admin**/private class Producer implements Runnable {public void run() {for (int i = 0; i < 20; i++) {produce("商品" + i);}}}/*** 消费者* @author admin**/private class Customer implements Runnable {public void run() {for (int i = 0; i < 20; i++) {consume();}}}public static void main(String[] args) {LockConditionTest2 lc = new LockConditionTest2();new Thread(lc.new Producer()).start();new Thread(lc.new Customer()).start();}
}

装饰器模式

为对象动态添加装修功能,它是从一个对象的外部来给对象添加功能,所以有非常灵活的扩展性。
抽象类写基础公共功能,继承类在其基础进行扩展。

重构代码:
大型重构指的是对顶层代码设计的重构,包括:系统、模块、代码结构、类与类之间的关系等的重构,重构的手段有:分层、模块化、解耦、抽象可复用组件等等。小型重构指的是对代码细节的重构,主要是针对类、函数、变量等代码级别的重构,比如规范命名、规范注释、消除超大类或函数、提取重复代码等等。

工厂模式

大部分工厂类都是以“Factory”这个单词结尾的,但也不是必须的,比如 Java 中的 DateFormat、Calender。除此之外,工厂类中创建对象的方法一般都是 create 开头,比如代码中的 createParser(),但有的也命名为 getInstance()、createInstance()、newInstance(),有的甚至命名为 valueOf()(比如 Java String 类的 valueOf() 函数)等等。
使用场景:
代码中存在 if-else 分支判断,动态地根据不同的类型创建不同的对象。针对这种情况,我们就考虑使用工厂模式,将这一大坨 if-else 创建对象的代码抽离出来,放到工厂类中。
还有一种情况,尽管我们不需要根据不同的类型创建不同的对象,但是,单个对象本身的创建过程比较复杂,比如要组合其他类对象,做各种初始化操作。在这种情况下,我们也可以考虑使用工厂模式,将对象的创建过程封装到工厂类中。

建造者模式

如果存在下面情况中的任意一种,我们就要考虑使用建造者模式:
我们把类的必填属性放到构造函数中,强制创建对象的时候就设置。如果必填的属性有很多,把这些必填属性都放到构造函数中设置,那构造函数就又会出现参数列表很长的问题。如果我们把必填属性通过 set() 方法设置,那校验这些必填属性是否已经填写的逻辑就无处安放了。如果类的属性之间有一定的依赖关系或者约束条件,我们继续使用构造函数配合 set() 方法的设计思路,那这些依赖关系或约束条件的校验逻辑就无处安放了。如果我们希望创建不可变对象,也就是说,对象在创建好之后,就不能再修改内部的属性值,要实现这个功能,我们就不能在类中暴露 set() 方法。构造函数配合 set() 方法来设置属性值的方式就不适用了。

public class ResourcePoolConfig {private String name;private int maxTotal;private int maxIdle;private int minIdle;private ResourcePoolConfig(Builder builder) {this.name = builder.name;this.maxTotal = builder.maxTotal;this.maxIdle = builder.maxIdle;this.minIdle = builder.minIdle;}//...省略getter方法...//我们将Builder类设计成了ResourcePoolConfig的内部类。//我们也可以将Builder类设计成独立的非内部类ResourcePoolConfigBuilder。public static class Builder {private static final int DEFAULT_MAX_TOTAL = 8;private static final int DEFAULT_MAX_IDLE = 8;private static final int DEFAULT_MIN_IDLE = 0;private String name;private int maxTotal = DEFAULT_MAX_TOTAL;private int maxIdle = DEFAULT_MAX_IDLE;private int minIdle = DEFAULT_MIN_IDLE;public ResourcePoolConfig build() {// 校验逻辑放到这里来做,包括必填项校验、依赖关系校验、约束条件校验等if (StringUtils.isBlank(name)) {throw new IllegalArgumentException("...");}if (maxIdle > maxTotal) {throw new IllegalArgumentException("...");}if (minIdle > maxTotal || minIdle > maxIdle) {throw new IllegalArgumentException("...");}return new ResourcePoolConfig(this);}public Builder setName(String name) {if (StringUtils.isBlank(name)) {throw new IllegalArgumentException("...");}this.name = name;return this;}public Builder setMaxTotal(int maxTotal) {if (maxTotal <= 0) {throw new IllegalArgumentException("...");}this.maxTotal = maxTotal;return this;}public Builder setMaxIdle(int maxIdle) {if (maxIdle < 0) {throw new IllegalArgumentException("...");}this.maxIdle = maxIdle;return this;}public Builder setMinIdle(int minIdle) {if (minIdle < 0) {throw new IllegalArgumentException("...");}this.minIdle = minIdle;return this;}}
}// 这段代码会抛出IllegalArgumentException,因为minIdle>maxIdle
ResourcePoolConfig config = new ResourcePoolConfig.Builder().setName("dbconnectionpool").setMaxTotal(16).setMaxIdle(10).setMinIdle(12).build();

可以把校验逻辑放置到 Builder 类中,先创建建造者,并且通过 set() 方法设置建造者的变量值,然后在使用 build() 方法真正创建对象之前,做集中的校验,校验通过之后才会创建对象。除此之外,我们把 ResourcePoolConfig 的构造函数改为 private 私有权限。这样我们就只能通过建造者来创建 ResourcePoolConfig 类对象。并且,ResourcePoolConfig 没有提供任何 set() 方法,这样我们创建出来的对象就是不可变对象了。

代理模式

  1. 代理模式的原理与实现在不改变原始类(或叫被代理类)的情况下,通过引入代理类来给原始类附加功能。一般情况下,我们让代理类和原始类实现同样的接口。但是,如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的。在这种情况下,我们可以通过让代理类继承原始类的方法来实现代理模式。

  2. 动态代理的原理与实现静态代理需要针对每个类都创建一个代理类,并且每个代理类中的代码都有点像模板式的“重复”代码,增加了维护成本和开发成本。对于静态代理存在的问题,我们可以通过动态代理来解决。我们不事先为每个原始类编写代理类,而是在运行的时候动态地创建原始类对应的代理类,然后在系统中用代理类替换掉原始类。

  3. 代理模式的应用场景代理模式常用在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志。我们将这些附加功能与业务功能解耦,放到代理类统一处理,让程序员只需要关注业务方面的开发。

94 设计模式(极客)相关推荐

  1. 设计模式之美-王争-极客时间-返现24元 限时优惠

    极客时间出品的<设计模式之美>由王争所作,王争是前Google工程师手把手教你写高质量代码 前Google工程师,<数据结构与算法之美>专栏作者.本专栏前Google工程师手把 ...

  2. 今日头条遭罚 94 万;快手、火山小视频整改「低俗」;Wi-Fi 万能钥匙被调查 | CSDN极客头条

    点击上方"CSDN",选择"置顶公众号" 关键时刻,第一时间送达! 「CSDN 极客头条」是从 CSDN 网站延伸至官方微信公众号的特别栏目,专注于一天业界事报 ...

  3. 本人亲自整理的极客时间设计模式之美的硬核笔记

    由于笔记内容过多,我把它放到语雀上了. 点击我 以下内容是为了让搜索引擎,检测到这篇文章.要阅读体验,请点击上面的连接"点击我",去我的语雀看.对了,我看到语雀那里有投诉的功能,请 ...

  4. 极客时间-设计模式之美 王争 听课笔记

    文章目录 极客时间-设计模式之美 王争 01 每个程序员都要尽早学习并掌握设计模式相关知识 02 哪些维度评判代码质量? 03 面向对象.设计原则.设计模式.编程规范.重构,这五者有何关系? 04 当 ...

  5. 极客Web前端开发资源大荟萃

    每周极客都将总结本周最精彩的素材提供给大家,希望可以带给你更多地灵感和帮助!极客#GB课程库#现已上线,无论你是初级.中级.还是正在进修的高级前端工程师.这里都将帮助你得到更多更高效的学习. #GB课 ...

  6. 京东程序员回应“被猝死”;淘宝特价版已提交微信小程序;苹果 M1 单核性能勇超 Intel 11 代 i7|极客头条...

    「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧. 整理 | 丁恩华 出品 | CSDN(ID:CSDNnews ...

  7. 微信Mac版更新:在电脑上刷朋友圈;领英暂停中国境内新用户注册;Git 恶意仓库可以在克隆时执行远程代码 | 极客头条...

    「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧. 整理 | 张红月 出品 | CSDN(ID:CSDNnews ...

  8. 西北大学研发猴脸识别技术;小米造车未立项;Linux Mint 警告用户安全意识落后 | 极客头条...

    「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧. 整理 | 丁恩华 出品 | CSDN(ID:CSDNnews ...

  9. 荣耀与美团合作推出 “共享笔记本”;传腾讯建议推出美国版微信,已被否;Debian 10.6 稳定版发布|极客头条

    整理 | 郑丽媛 头图 | CSDN 下载自东方 IC 「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧. 欢迎 ...

  10. 360 回应安全云盘出现交易异常;苹果官网陆续限购 iPhone;GitHub 屏蔽微软工程师的开源项目 | 极客头条...

    整理 | 屠敏 头图 | CSDN 下载自东方 IC 快来收听极客头条音频版吧,智能播报由标贝科技提供技术支持. 「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦 ...

最新文章

  1. mac运行python速度慢_python-3.x – Pygame简单循环在Mac上运行得非常慢
  2. jsp中两个double相乘_图像处理中的代数运算及几何变换
  3. centos中配置java视频教程_安装CentOs
  4. python解析html的库_用python解析html
  5. 中国电子云发布专属云CECSTACK 以全栈信创赋能千行百业
  6. [置顶]LGame框架问题汇总,有疑问请发至此文
  7. 关于application/x-www-form-urlencoded等字符编码的解释说明
  8. python骗局-说真的!大家做Python一定不要只会一个方向
  9. java.net.bindexception: address already in use: jvm_bind:8080
  10. windows10查看本机IP脚本
  11. 云计算的核心技术有哪些?
  12. 计算机用户名怎么改好听,电脑版本优酷视频如何设置呢称_昵称起名
  13. 速成实用硬笔字——最常用高频汉字前100
  14. 今天给大家介绍一下关于锂离子电池的负极材料选择
  15. 大数据离线流程(小练习)
  16. MSTAR数据集下载地址及处理方法
  17. 区块链SaaS云签章核心技术详解
  18. docker Alpine一个只有5M小而美的Docker镜像
  19. PHP课程网站络管理系统(源代码+论文)
  20. 用JSP做一个简单的抽奖页面

热门文章

  1. An Original Face Anti-spoofing Approach using Partial
  2. 分享Iteye的开涛对Ioc的精彩讲解
  3. MAC中TexLive+texmaker+JabRef引用文章
  4. Music Site
  5. (十)Spring中Bean的生命周期(下)
  6. oracle中取反_取反函数
  7. Keysight E8257D PSG 模拟信号发生器250kHz至50GHz
  8. 这些求职名词你真的看得懂吗?
  9. 机器学习模型评估的方法总结(回归、分类模型的评估)
  10. HM-帧内预测(概述)