设计模式(工厂模式,模板方法模式,单例模式)
单例模式:
确保一个类只有一个实例,并提供全局访问点。
单例模式举例:
-
配置信息类:用于存储应用程序的全局配置信息,例如数据库连接信息、日志配置等。
-
日志类:用于记录应用程序运行时的日志信息,确保在整个应用程序中只有一个日志实例
-
线程池类:在多线程环境下,使用单例模式可以确保只有一个线程池实例,提高资源利用率和性能。
单例模式饿汉式:
代码:
public class Singleton { /* 防止外界随意使用构造方法new对象,我们需要将构造私有化 */ private Singleton(){ } /* 为了赶紧new对象,我们new对象的时候变成静态的,让其随着类的加载而加载 为了不让外界随便使用类名调用此静态对象,我们将其变成private */ private static Singleton singleton = new Singleton(); /* 为了将内部new出来的对象给外界 我们可以定义 一个方法,将内部的对象返回给外界 */ public static Singleton getSingleton(){ return singleton; } }
将new出来的对象设置为静态属性,这样随着类的加载而加载
单例模式懒汉式:
public class Singleton1 { /* 防止外界随意使用构造方法new对象,我们需要将构造私有化 */ private Singleton1() { } /* 懒汉式,不着急new对象 */ private static Singleton1 singleton1 = null; /* 为了将内部new出来的对给外界 定义一个方法,将内部new出来的对返回 */ public static Singleton1 getSingleton1() { //如果singleton1不是null就没必要抢锁了,直接返回,是null再抢锁 if (singleton1==null){ synchronized (Singleton1.class){ if (singleton1 == null) { singleton1 = new Singleton1(); } } } return singleton1; } }
懒汉式就不着急new对象了,留了一个公共的接口,你想new的时候就new即可
懒汉式的线程不安全问题:
这也是懒汉式的一个缺点:如果没有加锁的代码:
public static Singleton1 getSingleton1() { if (singleton1 == null) { singleton1 = new Singleton1(); } return singleton1; }
这很容易引发线程不安全问题,我们设想有两个线程,第一个线程需要这个singleton1这个对象,进入了if判断,不过这个时候CPU将线程切换给了第二个线程,那这个时候,第二个线程也进入了if判断,然后CPU再切换会第一个线程,线程一创建了对象,但是我们知道线程二也进入了if判断,它也能创建对象,这就导致了线程不安全问题
饿汉式和懒汉式区别:
1:创建的时间不一样:饿汉式是在类加载过程中就创建了实例,而饿汉式是被调用的时候才创建实例
2:线程安全问题:饿汉式不存在什么线程安全,类加载的时候我就创建了,而且不能改,不可能又线程安全问题,反观饿汉式就有线程安全问题
在Spring中的单例模式的体现:
在 Spring 源码中,最常见的使用单例设计模式的场景就是在创建 Bean 实例时使用单例模式。Spring 容器默认情况下会将所有的 Bean 对象作为单例对象进行管理,这样可以节省资源,提高性能。
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry { private final Map singletonObjects = new ConcurrentHashMap(256); @Override public Object getSingleton(String beanName) { return this.singletonObjects.get(beanName); } @Override public void registerSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { Object oldObject = this.singletonObjects.get(beanName); if (oldObject != null) { throw new IllegalStateException("Could not register object [" + singletonObject + "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound"); } this.singletonObjects.put(beanName, singletonObject); } } // 其他方法... }
这个是我在鱼皮公众号上看到的,我第一次看到这段话的时候,也是有一个疑问
创建 Bean 实例是饿汉式还是懒汉式?
然后我问了GPT:
Spring容器在启动时会预先实例化所有单例Bean对象,这样可以避免懒汉式中可能存在的线程安全问题,确保在需要使用Bean时能够立即获取到对象实例。这种预先实例化的方式类似于饿汉式,但并不完全等同于饿汉式的实现方式。
模板方法模式:
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。明确了一部分功能,而另一部分功能不明确。需要延伸到子类中实现
这个我觉得就非常好理解:
我们平常都在写的接口或者抽象类都是这种思想
比如我们要去餐馆吃饭,我们每次餐馆都要点菜买单
不过我们去不同的餐馆点的菜都不一样
就可以把餐馆抽象成一个类,不同的餐馆都是实现类
上一段代码:
public abstract class Hotel { public void eat(){ System.out.println("点菜"); eatCai(); System.out.println("买单"); } public abstract void eatCai(); } public class QuanJuDe extends Hotel{ @Override public void eatCai() { System.out.println("薄饼"); System.out.println("放鸭肉"); System.out.println("酱"); System.out.println("葱丝"); System.out.println("黄瓜丝"); System.out.println("卷着吃"); } } public class ZhangLiang extends Hotel{ @Override public void eatCai() { System.out.println("调麻酱"); System.out.println("放辣椒油"); System.out.println("倒到大碗中吃"); } } public class Test01 { public static void main(String[] args) { QuanJuDe quanJuDe = new QuanJuDe(); quanJuDe.eat(); System.out.println("================"); ZhangLiang zhangLiang = new ZhangLiang(); zhangLiang.eat(); } }
工厂模式:
工厂模式是一种创建型设计模式,其主要目的是封装对象的实例化过程,将对象的创建和使用分离。通过工厂模式,可以实现更灵活、可扩展的对象创建方式,同时降低代码的耦合度。
工厂模式分为下面三种:简单工厂模式,工厂方法模式,抽象工厂模式
还没有工厂的时候:我们如果需要车,我们得自己去造车 自己去 new 对象
public class BMW320 { public BMW320(){ System.out.println("制造-->BMW320"); } } public class BMW523 { public BMW523(){ System.out.println("制造-->BMW523"); } } public class Customer { public static void main(String[] args) { BMW320 bmw320 = new BMW320(); BMW523 bmw523 = new BMW523(); } }
简单工厂模式:简单工厂的时候,我们已经有了简单的工厂,我们不用自己去造车了
我们可以告诉工厂,我们需要这个这个车,工厂造好给我们即可
有一个工厂类,我们去调用工厂类的造车方法造车
产品类:
// 产品接口 interface Product { void doSomething(); } // 具体产品类 A class ConcreteProductA implements Product { @Override public void doSomething() { System.out.println("Product A is doing something."); } } // 具体产品类 B class ConcreteProductB implements Product { @Override public void doSomething() { System.out.println("Product B is doing something."); } }
工厂类:
// 简单工厂类 class SimpleFactory { public static Product createProduct(String type) { if ("A".equals(type)) { return new ConcreteProductA(); } else if ("B".equals(type)) { return new ConcreteProductB(); } return null; } }
客户端代码:
// 客户端代码 public class Main { public static void main(String[] args) { Product productA = SimpleFactory.createProduct("A"); productA.doSomething(); Product productB = SimpleFactory.createProduct("B"); productB.doSomething(); } }
工厂方法模式:到了这个时候,随着车型的增多,一个工厂已经不能生成这么多车型了
就需要工厂分类:每个工厂生成一种型号的车
有一个工厂抽象类,生成各种型号的车的工厂去继承里面的造车方法
再有一个车的抽象类,不同的车去继承里面的方法
// 产品接口 interface Product { void doSomething(); } // 具体产品类 A class ConcreteProductA implements Product { @Override public void doSomething() { System.out.println("Product A is doing something."); } } // 具体产品类 B class ConcreteProductB implements Product { @Override public void doSomething() { System.out.println("Product B is doing something."); } } // 工厂接口 interface Factory { Product createProduct(); } // 具体工厂类 A,负责创建产品 A class ConcreteFactoryA implements Factory { @Override public Product createProduct() { return new ConcreteProductA(); } } // 具体工厂类 B,负责创建产品 B class ConcreteFactoryB implements Factory { @Override public Product createProduct() { return new ConcreteProductB(); } } // 客户端代码 public class Main { public static void main(String[] args) { Factory factoryA = new ConcreteFactoryA(); Product productA = factoryA.createProduct(); productA.doSomething(); Factory factoryB = new ConcreteFactoryB(); Product productB = factoryB.createProduct(); productB.doSomething(); } }
抽象工厂模式:这个时候的需求就已经很复杂了,
每个车需要的零件都不同,比如车1和车2分别是两个不同的型号,车1需要空调a和发动机b,车2需要空调b和发动机b
这个时候就设计到了一个产品族,就是空调,发动机或者其它产品合在一起就是一个产品族
有点像我们日常生活中开店,比如我们开冷冻产品店,那我们不可能一个人去准备所有的冷冻产品,我肯定是去找对应的供货商,比如火锅料的供货商,鱿鱼的供货商,饮料的供货商,然后整合到我这个冷冻店再去销售
所以翻译成Java语言就是,空调是一个抽象类,发动机是一个抽象类,多个抽象类,一个工厂抽象类,不同型号的车是一个类都去继承这个工厂,你需要什么零件就去这个工厂里面配这个零件。
// 产品族接口 interface AbstractProductA { void doSomething(); } interface AbstractProductB { void doSomething(); } // 具体产品类 A1 class ConcreteProductA1 implements AbstractProductA { @Override public void doSomething() { System.out.println("Product A1 is doing something."); } } // 具体产品类 B1 class ConcreteProductB1 implements AbstractProductB { @Override public void doSomething() { System.out.println("Product B1 is doing something."); } } // 具体产品类 A2 class ConcreteProductA2 implements AbstractProductA { @Override public void doSomething() { System.out.println("Product A2 is doing something."); } } // 具体产品类 B2 class ConcreteProductB2 implements AbstractProductB { @Override public void doSomething() { System.out.println("Product B2 is doing something."); } } // 抽象工厂接口 interface AbstractFactory { AbstractProductA createProductA(); AbstractProductB createProductB(); } // 具体工厂类 1 class ConcreteFactory1 implements AbstractFactory { @Override public AbstractProductA createProductA() { return new ConcreteProductA1(); } @Override public AbstractProductB createProductB() { return new ConcreteProductB1(); } } // 具体工厂类 2 class ConcreteFactory2 implements AbstractFactory { @Override public AbstractProductA createProductA() { return new ConcreteProductA2(); } @Override public AbstractProductB createProductB() { return new ConcreteProductB2(); } } // 客户端代码 public class Main { public static void main(String[] args) { AbstractFactory factory1 = new ConcreteFactory1(); AbstractProductA productA1 = factory1.createProductA(); AbstractProductB productB1 = factory1.createProductB(); productA1.doSomething(); productB1.doSomething(); AbstractFactory factory2 = new ConcreteFactory2(); AbstractProductA productA2 = factory2.createProductA(); AbstractProductB productB2 = factory2.createProductB(); productA2.doSomething(); productB2.doSomething(); } }