目录
一.设计模式
设计模式
学习设计模式的意义主要体现在以下几个方面:
-
提高设计能力:学习设计模式可以帮助开发人员理解和掌握各种设计原则和设计思想,提高设计能力,能够更好地进行系统设计和架构设计。
-
代码重用和维护:设计模式提供了一套通用的解决方案,可以避免重复造轮子,提高代码的重用性。同时,设计模式的使用也能够提高代码的可读性和可维护性,使代码更易于理解和修改。
-
提高团队合作效率:设计模式是一种标准化的解决方案,团队成员之间可以通过共享和理解设计模式来进行沟通和合作,提高团队的合作效率。
-
更好地理解和应用框架:许多框架和库都使用了设计模式,学习设计模式可以帮助开发人员更好地理解和应用这些框架,提高开发效率。
我们今天来详细了解面试常考的工厂模式和单例模式👀
二.工厂模式和单例模式
🐞单例模式
单例,顾名思义,也就是单个实例(instance),类的实例,就是对象
⌛有的人可能会想,那我多new几次,不就创建出多个对象了吗?🤔
⌛那么单例模式用途是什么呢?
接下来,我们看看在Java中如何实现单例模式.🤗
实际上,Java中实现单例模式有很多种写法,我们主要来学习这两种:
- 饿汉模式
- 懒汉模式
我们来看这段代码:
class Singleton{
//唯一实例的本体
private static Singleton instance =new Singleton();
//获取实例的方法
public static Singleton getInstance(){
return instance;
}
//禁止外部new对象
private Singleton(){
}
}
public class ThreadDemo17 {
public static void main(String[] args) {
//此时s1和s2调用得到的是同一个对象
Singleton s1=Singleton.getInstance();
Singleton s2=Singleton.getInstance();
//Singleton s3=new Singleton();
}
}
我们来具体分析这段代码:
具体是怎么回事呢?我们来进行详细介绍
懒汉模式来实现单例.主要的核心思想就是非必要,不创建
而饿汉就是提前创建好,直接可以使用
1.饿汉模式
代码如下:
//饿汉模式
class Singleton{
//唯一实例的本体
private static Singleton instance =new Singleton();
//获取实例的方法
public static Singleton getInstance(){
return instance;
}
//禁止外部new对象
private Singleton(){
}
}
2.懒汉模式
//懒汉模式
class SingletonLazy{
public static SingletonLazy instance=null;
public static SingletonLazy getInstance(){
if(instance==null){
instance=new SingletonLazy();
}
return instance;
}
private SingletonLazy(){
}
}
上面的代码并不难,但是有几个重要问题:
⌛以上两个代码,是否是线程安全的?
⌛多个线程下调用getInstance,是否会出现问题?
⌛代码中加上了synchorized,是为什么呢?
饿汉模式认为线程是安全的,因为只是读数据
但是懒汉模式在多线程下,却无法保证创建对象的唯一性.
(1)问题一:大量对象的创建
我们可以看到,懒汉模式需要进行判空,那么如果在空对象条件下突然有多个线程进行调用,就有可能创建出多个对象,这个时候就有可能会出现问题了.
这是因为对象有大有小,有些对象管理的内存数据可能会有很多,如果同时调用创建出这么多对象,线程就有可能会崩溃了.
所以,我们如何解决上述问题呢?办法就是加锁.
代码如下:
//懒汉模式
class SingletonLazy{
public static SingletonLazy instance=null;
public static SingletonLazy getInstance(){
if(instance==null){
synchronized (SingletonLazy.class){
instance=new SingletonLazy();
}
}
return instance;
}
private SingletonLazy(){
}
}
这样加上锁之后就能保证判定和new是一个原子操作,这样就可以避免同时创建出大量对象了.
(2)问题二:加锁导致阻塞等待
然而,加锁是一个比较低效的操作,因为加锁了就可能涉及到阻塞等待,所以我们的原则是非必要不加锁,那么,还有什么更好的办法吗?
我们可以修改代码形式以达到避免阻塞等待的目的。
我们来看看这个代码:
class SingletonLazy{
private static SingletonLazy instance=null;
public static SingletonLazy getInstance(){
if(instance==null){
synchronized (SingletonLazy.class){
if(instance==null){
instance=new SingletonLazy();
}
}
}
return instance;
}
private SingletonLazy(){
}
}
我们来对代码进行分析:
(3)问题三:指令重排序
但是,事情到这里就结束了吗?
上述代码其实还面临着一个很重要的问题——指令重排序
那么,这个问题如何来解决呢?
我们可以通过添加volatile来禁止指令重排序
具体代码如下:
class SingletonLazy{
volatile private static SingletonLazy instance=null;
public static SingletonLazy getInstance(){
if(instance==null){
synchronized (SingletonLazy.class){
if(instance==null){
instance=new SingletonLazy();
}
}
}
return instance;
}
private SingletonLazy(){
}
}
这样,就可以有效解决上述问题了
我们现在可以来总结一下了
单例模式具有线程安全问题
🐞工厂模式
工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的最佳方式。
工厂模式,实际上是用来填构造方法的坑的.因为构造方法如果想要提供多种不同的构造对象的方法,就得基于重载.
比如说我们想描述平面上的一个点,就有很大的问题.
这个时候,我们就可以通过构造一个工厂类来解决.
代码如下:
public class PointBuilder {
// 根据坐标创建 Point 对象
public static Point makePointByXY(double x, double y) {
return new Point(x, y);
}
// 根据极坐标创建 Point 对象
public static Point makePointByRA(double r, double a) {
double x = r * Math.cos(a);
double y = r * Math.sin(a);
return new Point(x, y);
}
}
三.总结分析
单例模式和工厂模式是两种常见的设计模式,它们在软件开发中具有不同的作用和应用场景。
在以后的学习中,应根据具体的需求和设计目标选择适合的设计模式..🤗