前言
什么是设计模式?
是广大程序员们总结汇总的一些编码套路,通常被用于底层内容的编写
单例模式
一个类只能被实例化一个对象
饿汉式
-
忽略需求,直接创建唯一实例
/*** 单例模式-饿汉式*/
public class ClassA {//用来返回的唯一实例//static:1.保证getClassA方法可以获取返回 2. 静态属性可以确保内存中只有一份//private:1. 防止外界任意访问属性,保障安全 2. 提升getClassA方法操作的必要性---》因为属性属于类的比较隐私的内容,因此直接访问是不合适的,并且使用方法进行获取,可以增加一些校验功能,提高操作的主动性private static ClassA ca = new ClassA();//用来被外界获取唯一对象的渠道//static :保证外界可以直接通过类名访问public static ClassA getClassA(){return ca;}//构造私有化:防止外界通过构造创建多个实例private ClassA(){}
}
-
缺点:有可能浪费空间,因为无论我们想不想使用这个类的对象,对象在类加载时就会创建,从而浪费空间
懒汉式
-
在获取实例时才会创建对象
-
如果不加synchronized同步,可能导致线程安全问题。(在if判断(cb==null)的地方,被线程中断,导致不同的线程都判定不存在对象,进而都去创建对象,从而发生了线程安全问题)
/*** 单例模式-懒汉式*/
public class ClassB {//用来返回的唯一实例//static:1.保证getClassA方法可以获取返回 2. 静态属性可以确保内存中只有一份//private:1. 防止外界任意访问属性,保障安全 2. 提升getClassA方法操作的必要性private static ClassB cb ;//用来被外界获取唯一对象的渠道//static :保证外界可以直接通过类名访问//synchronized:预防线程安全问题public synchronized static ClassB getClassB(){//只有第一次获取时需要实例化,其后直接将之前实例化的结果返回即可if (cb == null) {//调用该方法意味着需要获取实例,将cb属性实例化cb = new ClassB();}return cb;}//构造私有化:防止外界通过构造创建多个实例private ClassB(){System.out.println("正在执行无参构造...");}
}
-
缺点:线程效率慢---》改进:将同步方法改为同步代码块,但是此时我们属于开发者而不是使用者,我们只能在类的内部进行更改,而不是在外部使用同步方法,因此这里需要设计同步代码块的第二种写法
懒汉式-进阶版
-
在加锁的前提下,由同步方法更换为同步代码块,并结合二次校验尽可能提高线程效率
-
二次检验:虽然都是判断,但是意义不同,第一次是为了判定是否需要开启互斥锁,第二次才是去解决线程安全问题
/*** 单例模式-懒汉式*/
public class ClassB {//用来返回的唯一实例//static:1.保证getClassA方法可以获取返回 2. 静态属性可以确保内存中只有一份//private:1. 防止外界任意访问属性,保障安全 2. 提升getClassA方法操作的必要性private static ClassB cb ;//用来被外界获取唯一对象的渠道//static :保证外界可以直接通过类名访问public static ClassB getClassB(){//判断是否需要加锁:只有当线程判断cb为null时才有可能出现安全问题--》可以理解为线程安全问题不一定发生,因此可以加一个判断,继续优化代码(加锁必然导致线程效率拉低)if (cb == null) {//临界资源:当前类的类对象synchronized (ClassB.class){//只有第一次获取时需要实例化,其后直接将之前实例化的结果返回即可//防止线程安全问题的判断if (cb == null) {//调用该方法意味着需要获取实例,将cb属性实例化cb = new ClassB();}}}return cb;}//构造私有化:防止外界通过构造创建多个实例private ClassB(){System.out.println("正在执行无参构造...");}
}
懒加载
-
将功能内容交给静态内部类实现,外部类只负责调用
-
将操作的风险由外部类转移到内部类
/*** 单例模式-懒汉式*/
public class ClassB {//用来返回的唯一实例//static:1.保证getClassA方法可以获取返回 2. 静态属性可以确保内存中只有一份//private:1. 防止外界任意访问属性,保障安全 2. 提升getClassA方法操作的必要性private static ClassB cb ;private static class Inner{public static ClassB getClassB(){//判断是否需要加锁:只有当线程判断cb为null时才有可能出现安全问题if (cb == null) {//临界资源:当前类的类对象synchronized (ClassB.class){//只有第一次获取时需要实例化,其后直接将之前实例化的结果返回即可//防止线程安全问题的判断if (cb == null) {//调用该方法意味着需要获取实例,将cb属性实例化cb = new ClassB();}}}return cb;}}//用来被外界获取唯一对象的渠道//static :保证外界可以直接通过类名访问public static ClassB getClassB(){return Inner.getClassB();}public static void method(){System.out.println("111");}//构造私有化:防止外界通过构造创建多个实例private ClassB(){System.out.println("正在执行无参构造...");}
}
工厂模式
作用为简化数据量庞大时的操作负担,提高操作效率,常用于底层框架
工厂负责对象的创建和销毁这两个耗时的操作,多用于数据量庞大时提高效
案例需求
- 利用工厂模式管理学生对象的获取工作
-
步骤:
-
准备学生类
-
准备配置文件
-
准备工厂类
-
测试
-
-
实现:
-
学生类
public class Student {private String name;private int age;private double score;//省略getter、setter、构造、toString }
-
配置文件
-
右键项目新建file,创建一个后缀名为
.properties
配置文件 -
书写:
-
以
键=值
的格式书写-
键任意命名,不可重复
-
值为需要管理的类的全限定名
-
-
键和值都不可添加双引号
-
语句最后不加分号
-
一行只能书写一个键值对
-
语句中不能添加非法字符,如空格(空格是配置文件中很忌讳的东西,因为配置文件有时会识别空格)
-
StudentClassName=com.by.entity.Student
-
-
工厂类
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Properties;public class MyFactory {public static Student newStudent(){Student stu=null;try (//创建输入流FileInputStream fis=new FileInputStream("ClassNameManger.properties") //这个是配置文件名) {//读取配置文件,存储在集合中Properties p = new Properties();p.load(fis);//将流中的数据加载到properties集合中//获取全限定名String studentClassName = p.getProperty("StudentClassName");//获取学生类的类对象Class c = Class.forName(studentClassName);//构造学生实例返回stu =(Student) c.newInstance();} catch (Exception e) {System.out.println("未知异常");e.printStackTrace();}return stu;}}
4. 测试类
public class TestMyFactory {public static void main(String[] args) {//利用工厂类获取学生对象实例Student s1 = MyFactory.newStudent();s1.setName("zhangsan");s1.setAge(20);s1.setScore(88);System.out.println(s1);Student s2 = MyFactory.newStudent();}
}
总结
使用工厂模式的好处
- 解耦
- 通过工厂模式可以把对象的创建和使用过程分割开来。比如说 Class A 想调用 Class B的方法,那么我们无需关心B是如何创建的,直接去工厂获取就行。
- 减少代码量,易于维护
- 如果我们直接new一个对象时,如果需要的对象构造方法比较复杂,那么可能需要一连串的代码去创建对象,如果在别的类中又需要创建该对象,那么代码的重复度肯定不小(代码量庞大)。通过工厂模式的话,我们把对象创建的具体逻辑给隐藏起来了,交给工厂统一管理,这样不仅减少了代码量,以后如果想改代码的话,只需要改一处即可,也方便我们日常的维护。(减少代码量,并且便于维护)