Java的设计模式足有23种之多,
分类
按行为属性,结构属性可以分为三大类
创建型模式(5种):单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式
结构性模式(7种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式
常用的几种设计模式
1. 单例模式及线程安全问题
单例模式是非常常用的设计模式,他确保一个类只有一个对象,并且这个对象是自己创建的(通过IoC控制反转实现自己创建)。外界可以获取和使用这个对象
单例模式创建对象有“懒汉式”,“饿汉式”,单例模式构造方法私有化,外界无法创建,只能获取,下面两种单例实现:
饿汉式
package demo_singleton;
public class SingletonHungry {
//程序一加载就立马创建/实现对象
private static SingletonHungry singletonhunary = new SingletonHungry();
private SingletonHungry() {
}
public static SingletonHungry getinstance() {
return singletonhunary;
}
}
懒汉式
package demo_singleton;
/*懒汉式的单例模式,有线程安全问题,当多线程访问的时候,会出现多个实例*/
public class SingletonLazy {
private static SingletonLazy instance = null;
private SingletonLazy() {
}
public static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
加载期是早于运行期的,类加载发生在执行期,线程生成执行实在运行期,所以“饿汉式”不会遇到线程安全问题,“懒汉式”是getInstance获取对象时才创建对象(获取对象这行为是运行期的行为),如果此时刚好有多个线程同时调用getInstance()方法,就会发生线程并发安全问题。
“懒汉式”线程安全测试办法
同包下建一个测试类,继承Thread接口,重写run()方法,执行打印 懒汉式的getInstance()。创建多个线程,并start();
结果显示 对象的地址,如果多个线程输出的地址不一样,这说明发生线程并发问题。就不是我们想要的单例模式了。
详细参考 https://blog.youkuaiyun.com/qq_38663729/article/details/77584231
“懒汉式”单例模式线程并发问题优化
优化一
解决线程并发问题,首先想到的办法是同步,加上synchronized关键字
同步方法:
public static synchronized SingletonLazy1 getInstance(){
同步块:
public static SingletonLazy2 getInstance() {
synchronized (SingletonLazy2.class) {
if (instance2 == null) {
instance2 = new SingletonLazy2();
}
}
return instance2;
}
优化同步块:
当对象已经创建,线程再走到 条件(instance2 == null) 为假,当前线程还是要等待 之前线程释放锁,才能去判断不用创建对象,拜拜浪费时间去等解锁时间,还不如在锁外直接判断就可以跳过这个同步代码块“锁”。所以优化后:
public static SingletonLazy3 getInstance() {
if (instace3 == null) {
synchronized (SingletonLazy3.class) {
if (instace3 == null) {
instace3 = new SingletonLazy3();
}
}
}
return instace3;
}
还有另外一个想法,单例模式类只创建一个对象,这很符合静态类的特点,所以该类初始化创建对象写在静态块里。这已经不是“懒汉式”了。
package demo_singleton;
public class SingletonLazy4 {
private static SingletonLazy4 instance4 = null;
static{
instance4 = new SingletonLazy4();
}
public static SingletonLazy4 getInstance() {
return instance4;
}
private SingletonLazy4() {
}
}
利用静态内部类,内部类在编译的时候也是一个单独的class文件,在调用的时候会执行,不调用的时候不会执行。
package demo_singleton;
public class SingletonLazy5 {
private static class Sing {
private static SingletonLazy5 instance = new SingletonLazy5();
}
public static SingletonLazy5 getInstance() {
return Sing.instance;
}
private SingletonLazy5() {
}
}
注意:Java的反射机制也是可以破坏单例的。
2. 工厂模式
工厂模式的定义就是通过工厂创建对象,当用户需要创建打两把不同对象的时候,通过定义一个创建对象的接口,让子类自己决定创建哪一个对象,用户不再自行判断实例化哪一个对象不再去关心创建对象的复杂过程。我们通过创建一个工厂类,工厂类的作用就是判断需要创建拿一个对象,并实例化。
问得好:为什么不直接new不是更简单吗!问得好,这就是为什么工厂模式出现的意义:需求的变更贯穿于整个项目软件,设计模式的精髓就在于应对“未来的变化”,主要体现在程序的扩展性方面。个人理解:如果我面对的是一个固定的需求,那我用new创建对象没问题,但是往往我们需要处理的是5❀8?的需求,如果还是死程序,那是没道理的或者代码复杂的一批。工厂模式应运而生,它,实现不同需求创建不同对象。避免随便乱创建对象,保证代码健康。
未完待续,,,