设计模式

本文深入探讨了设计模式的重要性,包括六大设计原则:单一职责、迪米特、接口隔离、里氏替换、依赖倒置和开闭原则。详细介绍了工厂模式、策略模式和单例模式的实现及优缺点。此外,还提到了命令模式和代理模式的应用场景及其优势和劣势。通过对这些模式的理解,开发者可以写出更易扩展、维护和理解的代码,提升软件质量。
摘要由CSDN通过智能技术生成

设计模式,用来让你的代码可扩展、可维护、更容易理解;用抽象去构建框架,用实现去扩展细节,让你的代码高内聚、低耦合。

一 六大设计原则

单一职责原则

迪米特原则

接口隔离原则

里氏替换原则:不要破坏继承体系

依赖倒置原则 面向接口编程

开闭原则:总结性的 对扩展开放,对修改关闭

接口隔离原则和单一职责都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装的思想,但两者是不同的:

单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离。

单一职责原则主要是约束类,它针对的是程序中的实现和细节;接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建。

二 设计模式

1、工厂模式

不给业务端暴露创建的逻辑

工厂模式分为:

简单工厂模式

工厂方法模式 多态性工厂,把不同的产品实现类放到不同的工厂里,

抽象工厂模式

思考:为什么springMvc模式,用工厂创建been?

2、策略模式

策略模式是准备一组算法,并将这组算法封装到一系列的策略类里面

理解多态

多态的实现方式 重新、接口、抽象类和抽象方法

多态存在的三个必要条件

继承

重写

父类引用指向子类对象:Parent p = new Child();

策略模式的主要优点如下。

多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句,如 if…else 语句、switch…case 语句。

策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。

策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。

策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。

策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。

其主要缺点如下。

客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。

策略模式造成很多的策略类,增加维护难度

3、单例模式

单例对象的类必须保证只有⼀个实例存在

适⽤场景: 单例模式只允许创建⼀个对象,因此节省内存,加快对象访问速度,因此对象需要被公⽤的场

合适合使⽤,如多个模块使⽤同⼀个数据源连接对象等等。如:

  1. 需要频繁实例化然后销毁的对象。

  2. 创建对象时耗时过多或者耗资源过多,但⼜经常⽤到的对象。

  3. 有状态的⼯具类对象。

第一种:饿汉模式

public class HungrySingleton {

private static final HungrySingleton instance = new HungrySingleton();

private HungrySingleton() {

}

public static HungrySingleton getInstance() {

return instance;

}

}

优点:没有线程安全问题,简单

缺点:

1)提前初始化会延⻓类加载器加载类的时间;

2)如果不使用会浪费内存空间

3)不能传递参数

第二种:懒汉模式

public class LazySingleton {

private static volatile LazySingleton instance = null; //保证 instance 在所有线程中同步

private LazySingleton() {

} //private 避免类在外部被实例化

public static synchronized LazySingleton getInstance() {

//getInstance 方法前加同步

if (instance == null) {

instance = new LazySingleton();

}

return instance;

}

}

知识点:1、volatile

     volatile 线程间可见

    防止指令重排

2、 synchronized 锁定方法,保证线程安全

懒汉模式的缺点:

如果编写的是多线程程序,则不要删除上例代码中的关键字 volatile 和 synchronized,否则将存在线程非安全的问题。如果不删除这两个关键字就能保证线程安全,但是每次访问时都要同步,会影响性能,且消耗更多的资源,这是懒汉式单例的缺点。

3、静态方法和静态变量的区别(也是懒汉和饿汉的本质区别)

静态变量和静态代码块是类加载的时候执行

静态方法是调用的时候才会初始化

双重检查锁(double checked locking)

synchronized 由锁方法 变为 锁类
public class SingletonDoubleCheck {

private volatile static SingletonDoubleCheck singletonDoubleCheck;

private SingletonDoubleCheck() {


}

public static SingletonDoubleCheck getInstance() {
    if (null == singletonDoubleCheck) {
        synchronized (SingletonDoubleCheck.class) {
            if (null == singletonDoubleCheck) {
                singletonDoubleCheck = new SingletonDoubleCheck();
            }
        }

    }

    return singletonDoubleCheck;
}

}

知识点:1、synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

1)修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
  2) 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
  3)修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
  4)修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

2、双重检索的意义:第一个:保障性能,不用每次加锁

            第二个:保证线程安全

3、单例模式会被反射破坏,需要加下面这句话

private Singleton() {

if (null != SingletonClassInstance.instance)

throw new RuntimeException();

}

4、对象的生命周期:

单例的生命周期:spring 容器创建时就被创建,项目停止单例模式才会结束。

多例的生命周期:使用对象的时候才被创建,在jvm中垃圾回收

4、命令模式

分为抽象命令类、具体命令类、调用者类、接受者类

命令模式的优点

  1. 降低耦合度;

  2. 新的命令可以很容易的加入到系统中;

  3. 可以比较容易的设计一个命令队列和宏命令(组合命令);

  4. 可以方便的实现队请求的undo和redo;

命令模式的缺点

  1. 使⽤命令模式可能会导致某些系统有过多的具体命令类。因为针对每㇐个命令都需

要设计㇐个具体命 令类, 因此某些系统可能需要⼤量具体命令类,这将影响命令模

式的使⽤。

5、代理模式

使用场景:AOP 日志打印、异常处理、事务

1、静态代理

分为抽象角色、真实角色、代理角色(引用真实角色,在调用真实角色前后增强代码)。

优点:可以做到在不修改目标对象功能的基础上,对目标对象进行扩展。

缺点:

1)每一个代理类都要实现一遍目标类的接口,如果目标类增加了一个接口,那么代理类也必须跟着添加。

2)每一个代理类对应一个目标类对象,如果要代理的类对象比较多,那么代理类也会很多,代码会比较臃肿。

2、动态代理

1)Jdk动态代理

通过反射实现,能有效解决静态代理中代理类过多而代码臃肿的问题。

1> 必须是接口

if (!interfaceClass.isInterface()) {

7 throw new IllegalArgumentException(

8 interfaceClass.getName() + " is not an interface");

9 }

2>实现动态代理类实现InvocationHandler接⼝,并重写该invoke⽅法。

cjlib动态代理

动态代理类实现MethodInterceptor接口

如果目标对象没有实现接口,只能用cjlib动态代理。

原理:

CGLIB是⼀个强⼤的⾼性能的代码⽣成包,底层是通过使⽤⼀个⼩⽽快的字节码处理框架ASM,它可以在

运⾏期扩展Java类与实现Java接⼝

Enhancer是CGLIB的字节码增强器,可以很⽅便的对类进⾏拓展

使用的是继承

final修饰的类、方法不能使用cglib代理(如:wait() getClass);

创建代理对象的⼏个步骤:

1、⽣成代理类的⼆进制字节码⽂件

2、加载⼆进制字节码,⽣成Class对象( 例如使⽤Class.forName()⽅法 )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值