23种设计模式(更新中)-------总结b站自图灵学院设计模式教程

目录

设计模式

单例模式: Singleton

1.模式定义/应用场景/类图分析

模式定义:

应用场景:

类图分析:

2.加载模式:

1.懒汉模式: 延迟加载,只有在真正使用的时候,才开始实例化

2.饿汉模式:

3.静态内部类

工厂方法模式: Factory Method

模式定义:

简单工厂:(不是设计模式)

工厂方法模式:

应用场景:

主要优点:

源码中的应用:

抽象工厂模式: Abstract Factory

模式定义:

类图:

原始代码:

抽象工厂模式

应用场景:

优点:

在JDK源码中的应用:


设计模式

找到代码在 变化中稳定的部分, 才有导入设计模式价值.

稳定的代码和过于变化 没有规律的代码都没有导入设计模式的价值

单例模式: Singleton

1.模式定义/应用场景/类图分析

模式定义:

保证一个类只有一个实例,并且提供一个全局访问点

应用场景:

重量级的对象,不需要多个实例,如线程池,数据库连接池.

类图分析:

Singleton : 类名

singleton: Singleton 定义一个私有对象

Singleton() 构造方法私有化

getInstance() 公开的获取私有对象的方法

2.加载模式:

1.懒汉模式: 延迟加载,只有在真正使用的时候,才开始实例化

  • 优点:

    第一次调用时才初始化,避免内存浪费

  • 缺点:

    必须加锁才能保证单例,影响效率.

1)线程安全问题

多线程进行访问创建时,可能会出现线程安全问题.(加上Thread.sleep()可以使问题放大),破坏了单例的定义

public static LazySingleton getInstance(){
    if(instance == null){
        try{
            Thread.sleep(200);
        }catch(Exception e){
            e.printStackTrace();
        }
     	instance = new LazySingleton();   
    }
	return instance;
}

2)加锁优化

在获取对象的方法加上synchronized,能保证单例,但会损耗性能.

public synchronized static LazySingleton getInstance(){
    if(instance == null){
     	instance = new LazySingleton();   
    }
	return instance;
}

延迟加锁:

防止资源浪费,在instance判空后,进行加锁,在instance不为空时,不进行加锁.

由于在判空后进行加锁, 还是可能会出现线程安全问题.

所以在加锁后再进行一次判空

在加锁处还是可能会出现线程并发,资源浪费的问题.

public static LazySingleton getInstance(){
    if(instance == null){
    	synchronized (LazySingle.class){
            if(instance == null){
             	instance = new LazySingleton();    
                //字节码层 
                //JIT . CPU 
                //指令重排
                //1.分配空间
                //2.初始化
                //3.引用赋值
            }
    	}
    }
	return instance;
}

3)编译器(JIT),CPU有可能对指令进行重排序

导致使用到尚未初始化的实例,可以通过添加volatile关键字进行修饰,对于volatile修饰的字段,可以防止指令重排.

如果两个线程并发,

第一个线程执行了 (指令被重排)1,3步骤时(instance引用赋值了,但并未初始化)

此时第二个线程进来,在最外层判空为false,

直接返回,此时可能会出现空指针异常.

private volatile static LazySingleton instance;
private  LazeSingleton(){}
public...

2.饿汉模式:

 class HungrySingleton{
     private static HungrySingleton instance = new HungrySingleton();
     private HungrySingleton(){}
     public static HungrySingleton getInstance(){
         return instance;
     }
 }

类加载的初始化阶段就完成了实例的初始化.本质上就是借助于jvm类加载机制,保证实例的唯一性.

类加载过程:

  • 1.加载二进制数据到内存中,生成对应的Class数据结构,

  • 2.连接:

    a.验证 class文件是否符合jvm规范

    b.准备(给类的静态成员变量赋默认值),

    c.解析 如常量池中的符号引用转化成直接引用

  • 初始化:给类的静态变量赋初值.

jvm能保证以上三步操作只完成一次

只有在真正使用对应的类时,才会触发初始化.(如当前类是启动类即main函数所在类,直接进行new操作,访问静态属性,访问静态方法,用发射访问类,初始化一个类的子类等.)

  • 优点

    没有加锁,执行效率高

  • 缺点

    类加载时就初始化,浪费内存.

3.静态内部类

属于懒加载模式

class innerClassSingleton{
	private static class InnerClassHolder{
		private static InnerClassSingleton instance = new InnerClassSingleton();
	}
	private InnerClassSingleton{}
	public static InnerClassSingleton getInstance(){
		return InnerClassHoldler.instance();
	}
}

4.反射攻击

单例模式会被反射破坏

饿汉模式,静态内部类模式可以进行防护,懒汉模式没法进行防护.

//

枚举类型:

1)天然不支持反射创建对应的实例,且有自己的反序列化机制

2)利用类加载机制保证线程安全.

序列化:

1)可以利用指定方法来替换从反序列化流中的数据

序列化就是把一个java对象变成二进制内容,本质上就是一个byte[]数组.

为什么要把要把java对象序列化呢?

因为序列化后可以把byte[]数组保存到文件中或者通过网络传输到远程

反序列化:

就是把一个文件中的或者网络上接收到的二进制内容(即byte[]数组)变回java对象.

5.单例模式在Spring框架&JDK源码中的应用

工厂方法模式: Factory Method

模式定义:

定义一个用于创建对象的接口,让子类决定实例化哪一个类.

工厂方法模式的本质:

Factory Method使得一个类的实例化延迟到子类.

public class FactoryMethod {
    public static void main(String[] args) {
        Application application = new Application();
        ProductA product = application.getObject();
        product.method1();
    }
}


class ProductA {
    public void method1(){
        System.out.println("ProductA.method1.executed.");
    }
}

class Application{

    private ProductA createProduct(){
        // ... init
        // ...
        return new ProductA();
    }

    ProductA getObject(){
        ProductA product = createProduct();
        return product;
    }

}

简单工厂:(不是设计模式)

public class FactoryMethod {
    public static void main(String[] args) {
        Application application = new Application();
        Product product = application.getObject("0");
        product.method1();
    }
}

interface Product{
    public void method1();
}

class ProductA implements Product{
    public void method1(){
        System.out.println("ProductA.method1.executed.");
    }
}
class ProductA1 implements Product{
    public void method1(){
        System.out.println("ProductA1.method1.executed.");
    }
}
class SimpleFactory{
    public static Product createProduct(String type){
        if (type.equals("0")){
            return new ProductA();
        }else if (type.equals("1")){
            return new ProductA1();
        }else {
            return null;
        }
    }
}

class Application{

    private Product createProduct(String type){
        // ... init
        // ...

        return SimpleFactory.createProduct(type);
    }

    Product getObject(String  type){
        Product product = createProduct(type);
        return product;
    }

}

工厂方法模式:

分析:

这段代码中,product对象的创建是稳定的

Product的对象的种类是变化的,可能是product1,可能是product2

开闭原则(OPEN CLOSE):对拓展开放,对修改关闭.

public class FactoryMethod {
    public static void main(String[] args) {
        Application application = new ConcerateProductA();
        Product product = application.getObject();
        product.method1();
    }
}

interface Product{
    public void method1();
}

class ProductA implements Product{
    public void method1(){
        System.out.println("ProductA.method1.executed.");
    }
}
class ProductA1 implements Product{
    public void method1(){
        System.out.println("ProductA1.method1.executed.");
    }
}
class SimpleFactory{
    public static Product createProduct(String type){
        if (type.equals("0")){
            return new ProductA();
        }else if (type.equals("1")){
            return new ProductA1();
        }else {
            return null;
        }
    }
}

abstract class Application{

    /*把稳定的部分定义成抽象,让子类去实现*/
    abstract Product createProduct();

    Product getObject(){
        Product product = createProduct();
        //..
        //..
        return product;
    }

}

/*子类具体实现父级的抽象方法*/
class ConcerateProductA extends Application{

    @Override
    Product createProduct() {
        //...
        return new ProductA();
    }
}

应用场景:

  1. 当你不知道该使用对象的确切类型的时候

  2. 当你希望为库或框架提供扩展其内部组件的方法时

主要优点:

  1. 将具体产品和创建者解耦

  2. 符合单一职责原则

  3. 符合开闭原则

源码中的应用:

//java api
//静态工厂方法
	Calender.getInstance()
	java.text.NumberFormat.getInstance()
	java.util.ResourceBundle.getBundle()
    
//工厂方法
	java.net.URLStreamHandlerFactory	//流协议处理的通用超类
    javax.xml.bind.JAXBContext.createMarshaller

抽象工厂模式: Abstract Factory

模式定义:

提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类.

(一组工厂方法的接口, 一系列相关的,互相依赖的产品组成的一组接口 就是抽象工程模式)

本质就是是由一些工厂方法模式组合而成.

类图:

原始代码:

public class AbstractFactoryTest {
    public static void main(String[] args) {
        IDatabaseUtils iDatabaseUtils = null;
        IConnection connection = iDatabaseUtils.getConnection();
        connection.connect();
        ICommand command = iDatabaseUtils.getCommand();
        command.command();
    }
}
//  变化:  mysql , oracle ...
//          connection, command,

interface IConnection{
    void connect();
}

interface ICommand{
    void command();
}

interface IDatabaseUtils{
    IConnection getConnection();
    ICommand getCommand();
}

抽象工厂模式

public class AbstractFactoryTest {
    public static void main(String[] args) {
        IDatabaseUtils iDatabaseUtils = new OracleDataBaseUtils();
        IConnection connection = iDatabaseUtils.getConnection();
        connection.connect();
        ICommand command = iDatabaseUtils.getCommand();
        command.command();
    }
}
//  变化:  mysql , oracle ...
//  不变:  connection, command,

/*定义connection规范*/
interface IConnection{
    void connect();
}

/*定义command规范*/
interface ICommand{
    void command();
}

/*定义databaseutils规范*/
interface IDatabaseUtils{
    IConnection getConnection();
    ICommand getCommand();
}

class MysqlConnection implements IConnection{

    @Override
    public void connect() {
        System.out.println("mysql connection...");
    }
}

class OracleConnection implements IConnection{

    @Override
    public void connect() {
        System.out.println("oracle connection...");
    }
}

class MysqlCommand implements ICommand{

    @Override
    public void command() {
        System.out.println("mysql command...");
    }

}

class OracleCommand implements ICommand{

    @Override
    public void command() {
        System.out.println("oracle command...");
    }
}

class MysqlDataBaseUtils implements IDatabaseUtils{

    @Override
    public IConnection getConnection() {
        return new MysqlConnection();
    }

    @Override
    public ICommand getCommand() {
        return new MysqlCommand();
    }
}

class OracleDataBaseUtils implements IDatabaseUtils{

    @Override
    public IConnection getConnection() {
        return new OracleConnection();
    }

    @Override
    public ICommand getCommand() {
        return new OracleCommand();
    }
}

应用场景:

程序需要处理不同系列的相关产品,但是您不希望他依赖于这些产品的具体类时,可以使用抽象工厂

优点:

  1. 可以确信你从工厂得到的产品彼此是兼容的

  2. 可以避免具体产品和客户端代码之间的紧密耦合

  3. 符合单一职责原则

  4. 符合开闭原则

在JDK源码中的应用:

java.sql.Connection
java.sql.Driver

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值