首页 > 编程语言 >Java设计模式-单例模式和工厂模式的思路解析

Java设计模式-单例模式和工厂模式的思路解析

时间:2024-10-30 09:18:22浏览次数:7  
标签:Java cb ClassB 模式 实例 static private 设计模式 public

前言

什么是设计模式?

是广大程序员们总结汇总的一些编码套路,通常被用于底层内容的编写

单例模式

一个类只能被实例化一个对象

饿汉式

  • 忽略需求,直接创建唯一实例

/**
 * 单例模式-饿汉式
 */
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("正在执行无参构造...");
    }
}

 工厂模式

作用为简化数据量庞大时的操作负担,提高操作效率,常用于底层框架

工厂负责对象的创建和销毁这两个耗时的操作,多用于数据量庞大时提高效

案例需求

  • 利用工厂模式管理学生对象的获取工作
  • 步骤:

    1. 准备学生类

    2. 准备配置文件

    3. 准备工厂类

    4. 测试

  • 实现:

  1. 学生类

    public class Student {
        private String name;
        private int age;
        private double score;
        //省略getter、setter、构造、toString
    }
  2. 配置文件

    • 右键项目新建file,创建一个后缀名为.properties配置文件

    • 书写:

      1. 键=值的格式书写

        • 键任意命名,不可重复

        • 值为需要管理的类的全限定名

      2. 键和值都不可添加双引号

      3. 语句最后不加分号

      4. 一行只能书写一个键值对

      5. 语句中不能添加非法字符,如空格(空格是配置文件中很忌讳的东西,因为配置文件有时会识别空格)

    StudentClassName=com.by.entity.Student
  3. 工厂类

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一个对象时,如果需要的对象构造方法比较复杂,那么可能需要一连串的代码去创建对象,如果在别的类中又需要创建该对象,那么代码的重复度肯定不小(代码量庞大)。通过工厂模式的话,我们把对象创建的具体逻辑给隐藏起来了,交给工厂统一管理,这样不仅减少了代码量,以后如果想改代码的话,只需要改一处即可,也方便我们日常的维护。(减少代码量,并且便于维护)

标签:Java,cb,ClassB,模式,实例,static,private,设计模式,public
From: https://blog.csdn.net/weixin_52937170/article/details/143302689

相关文章

  • 基于Java语言的高能耗企业 水-电-气-热-油-空压机等数据采集系统-能源管理系统-在线监
    一、介绍基于SpringCloud的能管管理系统-能源管理平台源码-能源在线监测平台-双碳平台源码-SpringCloud全家桶-能管管理系统源码二、软件架构 二、功能介绍 三、数字大屏展示 四、数据采集原理 五、软件截图           ......
  • Java语言的Netty框架+云快充协议1.5+充电桩系统+新能源汽车充电桩系统源码
    云快充协议+云快充1.5协议+云快充1.6+云快充协议开源代码+云快充底层协议+云快充桩直连+桩直连协议+充电桩协议+云快充源码介绍云快充协议+云快充1.5协议+云快充1.6+云快充协议开源代码+云快充底层协议+云快充桩直连+桩直连协议+充电桩协议+云快充源码软件架构1、提供云快......
  • 实验6:原型模式(向量的原型)
    [实验任务一]:向量的原型用C++完成数学中向量的封装,其中,用指针和动态申请支持向量长度的改变,使用浅克隆和深克隆复制向量类,比较这两种克隆方式的异同。 1.类图   2. 源代码(1) 浅克隆代码和运行结果#include<bits/stdc++.h>usingnamespacestd;classVector......
  • 实验7:单例模式(学号的单一 )
    [实验任务一]:学号的单一仿照课堂的身份证的例子,实现每个同学仅有一个学号这一问题。1. 类图 1. 源代码//StudentID.javapackagetest7; publicclassStudentID{    privatestaticStudentIDinstance=null;    privateStringid;     privat......
  • 每日OJ题_牛客_AB20走迷宫_BFS_C++_Java
    目录牛客_AB20走迷宫_BFS题目解析C++代码Java代码牛客_AB20走迷宫_BFS走迷宫_牛客题霸_牛客网(nowcoder.com)描述:        给定一个n×m的网格,在网格中每次在不超过边界的情况下可以选择向上、向下、向左、向右移动一格。网格中的一些格子上放置有障碍物,放有......
  • 【JavaSE】认识String类,了解,进阶到熟练掌握
    #1024程序员节|征文#下面就让博主带领大家一起解决心中关于String类的疑问吧~~~1.字符串构造:第一种和第二种(有一定的区别,在常量池上)publicstaticvoidmain(String[]args){//使用常量串构造Strings1="hello";System.out.println(s1);//直接newString对象S......
  • 13.Java的IO流
    文件概念文件:保存数据的地方。文件流:文件在程序中是以流的形式来操作的。流:数据在数据源(文件)和程序(内存)之间经历的路径。输入流:数据从数据源(文件)到程序(内存)的路径。输出流:数据从程序(内存)到数据源(文件)的路径。常用操作构造方法方法说明File(Fileparent,......
  • javascript-Web APLs (三)
     事件流指的是事件完整执行过程中的流动路径 说明:假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段 简单来说:捕获阶段是从父到子冒泡阶段是从子到父 实际工作都是使用事件冒泡为主事件捕获DOM.addEventListener(事件类型,事件处......
  • 从零开始的JavaScript基础!
    目录一、JavaScript的概述二、如何在HTML页面中使用JS(一)、行内式 (二)、内嵌式(三)、外链式(四)、基本执行顺序1.从上到下线性执行:2.阻塞行为:(五)、JS输出方式1. alert() 通过浏览器弹出框进行输出 2.document.write() 直接在网页页面中进行输出 3.console.log()......
  • 基于Java+SpringBoot+Mysql实现的古诗词平台功能设计与实现七
    一、前言介绍:1.1项目摘要随着信息技术的迅猛发展和数字化时代的到来,传统文化与现代科技的融合已成为一种趋势。古诗词作为中华民族的文化瑰宝,具有深厚的历史底蕴和独特的艺术魅力。然而,在现代社会中,由于生活节奏的加快和信息获取方式的多样化,古诗词的传播和阅读面临着一定的挑......