设计模式

总概述

设计模式是一套被反复使用的、多数人知晓的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。

1.单例模式

Java中单例(Singleton)模式是一种广泛使用的设计模式。单例模式的主要作用是保证在Java程序中,某个类只有一个实例存在。单例模式有很多好处,它能够避免实例对象的重复创建,不仅可以减少每次创建对象的时间开销,还可以节约内存空间;能够避免由于操作多个实例导致的逻辑错误。

Ⅰ 饿汉式-线程安全
采取直接实例化 uniqueInstance 的方式就不会产生线程不安全问题。但是直接实例化的方式丢失了延迟实例化带来的节约资源的好处在这里插入图片描述
Ⅱ 懒汉-线程不安全
私有静态变量 Singleton 被延迟实例化,这样做的好处是,如果没有用到该类,那么就不会实例化 Singleton,从而节约资源。
这个实现在多线程环境下是不安全的,如果多个线程能够同时进入 if (singleton== null) ,并且此时 singleton 为 null,那么会有多个线程执行 singleton = new Singleton(); 语句,这将导致实例化多次 Singleton。
在这里插入图片描述
Ⅲ 懒汉式-线程安全
只需要对 getUniqueInstance() 方法加锁,那么在一个时间点只能有一个线程能够进入该方法,从而避免了实例化多次 uniqueInstance。
但是当一个线程进入该方法之后,其它试图进入该方法的线程都必须等待,即使 uniqueInstance 已经被实例化了。这会让线程阻塞时间过长,因此该方法有性能问题,不推荐使用。
在这里插入图片描述
Ⅳ 双重校验锁-线程安全
Singleton只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行,只有当 Singleton没有被实例化时,才需要进行加锁。
双重校验锁先判断Singleton是否已经被实例化,如果没有被实例化,那么才对实例化语句进行加锁。
在这里插入图片描述
在 singleton == null 的情况下,如果两个线程都执行了 if 语句,那么两个线程都会进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 singleton = new Singleton(); 这条语句,只是先后的问题,那么就会进行两次实例化。因此必须使用双重校验锁,也就是需要使用两个 if 语句。

singleton 采用 volatile 关键字修饰也是很有必要的, singleton= new Singleton(); 这段代码其实是分为三步执行:
(1)为 singleton 分配内存空间
(2)初始化 singleton
(3)将 singleton 指向分配的内存地址

但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1>3>2。指令重排在单线程环境下不会出现问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如,线程 T1 执行了 1 和 3,此时 T2 调用 getUniqueInstance() 后发现 uniqueInstance 不为空,因此返回 uniqueInstance,但此时 uniqueInstance 还未被初始化。
使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。

Ⅴ.单例模式的应用

  • 在计算机系统中,线程池、日志对象、打印机、显卡的驱动程序对象常被设计成单例。
  • 网站计数器(统计网站在线人数)

二. 简单工厂(Simple Factory)

在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口。
简单工厂把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个具体子类来实例化。
在这里插入图片描述
实现
在这里插入图片描述
以下的 SimpleFactory 是简单工厂实现,它被所有需要进行实例化的客户类调用。
在这里插入图片描述
在这里插入图片描述

三. 工厂方法(Factory Method)

定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。

在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。
下图中,Factory 有一个 doSomething() 方法,这个方法需要用到一个产品对象,这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。
在这里插入图片描述
实现
在这里插入图片描述

四、抽象工厂(Abstract Factory)

提供一个接口,用于创建 相关的对象家族 。
抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂方法模式只是用于创建一个对象,这和抽象工厂模式有很大不同。

实现:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
几个工厂模式解析可以参考:https://www.jianshu.com/p/bf95623bdeee

五、代理模式

代理模式概念理解:我自己能做的事情,让别人代替我来做,例如,我点了份菜,可以自己下楼去拿,但我现在比较忙,就让外卖小哥帮忙送上来,这块,外卖小哥就充当一个中间人的角色,帮我把事情做了。

5.1 静态代理
代理类由程序员自己实现的。就是再定义一个实现被代理类所实现的接口的代理类。

public interface People {
    public void execute();

}
public class My implements People {
    @Override
    public void execute() {
         System.out.println("拿外卖");

    }
}
public class WaiMaiXiaoGe implements People {
    public My my;
    public WaiMaiXiaoGe(My my){
        this.my=my;
    }
    @Override
    public void execute() {
        System.out.println("打包外卖");
        my.execute();
        System.out.println("送外卖结束");
    }
}

5.2 动态代理

参考:https://blog.csdn.net/wangpei555/article/details/70473615#commentBox

六、适配器模式

把一个类接口转换成另一个用户需要的接口。
鸭子(Duck)和火鸡(Turkey)拥有不同的叫声,Duck 的叫声调用 quack() 方法,而 Turkey 调用 gobble() 方法。
要求将 Turkey 的 gobble() 方法适配成 Duck 的 quack() 方法,从而让火鸡冒充鸭子!

public interface Duck {
    void quack();
}
public interface Turkey {
    void gobble();
}
public class WildTurkey implements Turkey {
    @Override
    public void gobble() {
        System.out.println("gobble!");
    }
}
public class TurkeyAdapter implements Duck {
    Turkey turkey;

    public TurkeyAdapter(Turkey turkey) {
        this.turkey = turkey;
    }
    
    @Override
    public void quack() {
        turkey.gobble();
    }
}
public class Client {
    public static void main(String[] args) {
        Turkey turkey = new WildTurkey();
        Duck duck = new TurkeyAdapter(turkey);
        duck.quack();
    }
}

JKD中的适配器模式:
java.util.Arrays#asList() 可以把数组类型转换为 List 类型。

@SafeVarargs
public static <T> List<T> asList(T... a)

应该注意的是 asList() 的参数为泛型的变长参数,不能使用基本类型数组作为参数,只能使用相应的包装类型数组。

Integer[] arr = {1, 2, 3};
List list = Arrays.asList(arr);

七、迭代器模式

Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值