这里只是简单记录我学习过程中的对各种设计模式的理解,没有具体实现代码
前情
学习设计模式,我觉得最重要的不止是如何使用,还有为什么使用,甚至后者比之前者有过之而无不及.有一本书《大话设计模式》很受欢迎,我觉得原因其是将各种设计模式的使用环境设计成一个个场景,用对话的形式来表示;所以我会从为什么使用/使用场景和如何使用两个方面来叙述;
正文
单例模式
- 使用原因 : 在我们的系统中,有一些对象我们只需要一个实例对象,比如线程池,缓存,日志对象,驱动程序等等;这些场景中,有一些使用单例模式是为了避免创建多个对象,减少了内存访问和GC的压力,但是还有一些是必须使用单例模式,因为如果是多例,会导致不一致的情况;
- 使用 :
-
基本要求: 单例类必须提供一个private修饰的构造器,保证该单例类不会在其他类中直接实例化,还有就是内部的实例
instance
和返回实例的方法需要static修饰,因为我们只能通过类方法获得实例; -
饿汉式 : 在逻辑层面是指JVM装载类的时候就对单例对象进行实例化,代码层面是值在单例对象声明时进行实例化
-
懒汉式 : 在逻辑层面指在使用返回实例方法时才进行实例化,代码层面是在返回方法内部创建实例
-
懒汉式有个问题,就是我们在多线程下,多个线程同时访问返回实例方法,如何保证只实例一次,有几种解决办法:
- synchronized同步方法,使用synchronized修饰返回实例的方法,保证只有一个线程进入实例化,然后在内部判断全局实例对象是否已经进行实例化即可;但是synchronized锁粒度太大,不建议使用;
- 双重判断:不加锁,在方法内部先判断实例对象是否被实例化,如果没有,对当前类加synchronized锁,在同步代码内部再次进行判断实例对象是否被实例化,如果没有进行实例化,之所以进行第二次判断是因为进入第一层判断的线程可能会被调度失去运行机会,再次获得执行机会时可能已经有其他线程进行实例化;双重判断虽然也使用了synchronized,但是锁的是当前类,而且是在一次判断后,比之同步方法,锁的粒度小了很多;
- 静态内部类: 没有锁,利用静态内部类的特点,将实例对象的声明和实例化的写入当前类的一个静态内部类中,因为静态内部类的初始化只有被调用时才会开始,所以在使用时调用静态内部类,起到懒汉的作用;
-
有一个单例模式的实现方法被很多书和博客推崇,就是枚举实现单例模式,就是将当前单例类声明为一个枚举,然后实例对象就是其内的一个元素,虽然这是一个饿汉式的单例模式,但是解决了单例模式和序列化的冲突,而且实现很简单;
-
工厂模式
-
为什么要使用工厂模式 :
- 解耦 : 将创建对象和使用对象分开
- 减少代码重复 : 如果创建一个对象十分复杂,那么在一个系统中,就会出现很多重复的代码 ;
- 降低维护成本 : 如果一个类的实例化过程需要修改,那有多少地方实例化修改多少处代码;
简单工厂模式
- 适应场景 : 创建对象少,使用方不关心创建过程
- 实现 : 创建一个工厂类A,A主要有一个条件判断语句(switch/if-else),根据不同的情况创建不同的对象;
- 不好的地方 : 如果需要添加/删除一些情况和对应的对象,就需要修改工厂类,违背了面向对象开放-封闭原则
- 改进 : 使用反射代替判断语句,不违反开发-封闭原则
工厂模式
- 适应场景 : 很虚的话,不说了
- 实现 : 每一个具体的类有一个对应的工厂类,多个工厂类实现同一个接口
抽象工厂
- 适应场景 : 需要组合一些类共同完成任务
- 实现: 举个例子,系统和枪支有关,我们为了描述各种枪和子弹,需要组合枪和对应的子弹,我们需要创建一个枪接口,一个子弹接口,然后创建对应的实现类AK,AK-子弹,M4,M4-子弹,然后创建一个工厂接口F,F内部包含包含返回枪接口和子弹接口的抽象方法,然后创建AK工厂和M4工厂,客户端使用的时候,直接实例化AK工厂,然后调用响应的工厂方法;