1、设计模式概念及分类
简单来说设计模式是被广大程序员们总结并认可的编码套路,其中最常用的莫过于单例模式与工厂模式,而单例模式也有更加细的分类,一起来学习一下这些模式的用法和特点吧。
2、单例模式
一个类只能被实例化出来一个对象
2.1、饿汉式
无论如何,都会创建出来一个对象
思路:
在类中直接实例化一个用来返回的对象,再为外界提供一个获取该对象的方法
缺点:有可能造成空间浪费
代码解释:
/** * 单例模式-饿汉式 */ public class ClassA { //唯一的、全局的、私有的、用来返回的对象实例 private static ClassA ca=new ClassA(); //方法:用来被外界调用,从而获取该类的唯一实例 //static:为了使外界直接通过类名调用该方法 public static ClassA getClassA(){ return ca; } //私有化构造:避免外界通过构造创建该类的对象 private ClassA(){} } public class Test { public static void main(String[] args) { ClassA ca1=ClassA.getClassA(); ClassA ca2=ClassA.getClassA(); System.out.println(ca1==ca2);//true } }
相当于类加载,ca1和ca2都是类对象,为同一个对象,要与类的对象有所区分。
2.2、懒汉式
思路:只有当需要创建唯一实例时,才会在对应方法中进行实例化
使用synchronized来同步方法
缺点:同步方法效率太慢,线程效率低
代码解释:
/** * 单例模式-懒汉式 */ public class ClassB { //声明用来返回的对象引用 private static ClassB cb=null; //synchronized:避免线程安全问题 public synchronized static ClassB getClassB(){ if (cb==null){//非空判断,避免重复创建 cb=new ClassB(); } return cb; } //私有化构造 private ClassB(){} }
这里利用了synchronized来防止重复创建实例化对象:如果事先没有创建,那就新创建,不会浪费空间。
2.2.1、懒汉式进阶版
思路:在保证线程安全的基础上,最大程度提高线程效率
使用synchronized来同步代码块
代码演示:
/** * 单例模式-懒汉式进阶版 */ public class ClassB2 { //声明用来返回的对象引用 private static ClassB2 cb=null; //synchronized:避免线程安全问题 public static ClassB2 getClassB2(){ if (cb==null){//非空判断,避免重复创建 synchronized (ClassB2.class){ if (cb==null){//二次校验,如果出现了线程安全问题,最大程度保证数据安全 cb=new ClassB2(); } } } return cb; } //私有化构造 private ClassB2(){} }
同步代码块会使程序运行效率提升,因为此时只需时间片就可以执行此线程。
2.2.2、懒汉式之懒加载
思路:在懒汉式的基础上,将获取自己类实例的任务交给静态内部类完成
public class ClassC { //声明用来返回的对象引用 private static ClassC cc=null; //静态内部类:获取ClassC的唯一实例 private static class ClassC2{ //synchronized:避免线程安全问题 public static ClassC get(){ if (cc==null){//非空判断,避免重复创建 synchronized (ClassC.class){ if (cc==null){//二次校验,如果出现了线程安全问题,最大程度保证数据安全 cc=new ClassC(); } } } return cc; } } public static ClassC getClassC(){ return ClassC2.get(); } //私有化构造 private ClassC(){} }
这种方式效果跟懒汉式的进阶类似,只不过是将加载交给了静态内部类,效率更高。
3、工厂模式
特点:
常用于框架
自身不再直接创建对象,交给 “工厂” 完成,需要对象时直接调用工厂的指定方法获取
步骤:
书写实体类,用来构建对象
书写.properties配置文件,存放工厂使用反射时需要的类信息
书写工厂类,创建对象
书写测试类
用一个实例演示:
3.1、书写实体类
public class Student { private String name; private int age; private double score; //此处省略getter与setter方法 public Student() { } public Student(String name, int age, double score) { this.name = name; this.age = age; this.score = score; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", score=" + score + '}'; } }
3.2、新建配置文件.properties
右键项目名创建一个后缀名为.properties的配置文件
文件内容:
键(自定义)=值(类的全限定名)
例如:StudentClassName=com.bz.entity.Student
结构特点:
键不可重复
等号左右无双引号
整条语句不要存在多余空格
末尾无分号
一行只能有一个键值对
3.3、书写工厂类并创建对象
/** * 工厂类 */ public class MyFactory { //书写获取Student实例的方法 //static:方便直接通过类名调用 public static Student getStudent(){ Student stu=null; try ( //创建字节输入流对象 FileInputStream fis = new FileInputStream("Factory.properties"); //添加缓冲流 BufferedInputStream bis = new BufferedInputStream(fis); ) { //创建用来接收配置文件信息的Properties集合 Properties p = new Properties(); //通过load方法将配置文件读取值集合中 p.load(bis); //获取全限定名 String str= p.getProperty("StudentClassName"); //获取类对象 Class c = Class.forName(str); //利用无参构造构建类的对象 stu=(Student) c.newInstance(); }catch (FileNotFoundException e){ System.out.println("文件路径不正确"); }catch (IOException e){ System.out.println("读取失败"); }catch (Exception e){ System.out.println("未知异常!"); e.printStackTrace(); } return stu; } }
3.4、对工厂类测试
public class TestMyFactory { public static void main(String[] args) { //利用工厂获取学生对象 Student stu = MyFactory.getStudent(); stu.setName("张三"); stu.setAge(20); stu.setScore(78); System.out.println(stu); } }
到这里有关设计模式单例模式与工厂模式就分享结束了,最后祝大家国庆节high起来,心情愉快!