设计模式

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

六大设计原则

   单一职责原则

   迪米特原则

   接口隔离原则

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

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

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

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

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

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

 

设计模式

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;

}

}

知识点:1volatile

         volatile 线程间可见

        防止指令重排

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

懒汉模式的缺点:

如果编写的是多线程程序,则不要删除上例代码中的关键字 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. 可以方便的实现队请求的undoredo

命令模式的缺点

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

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

式的使⽤。

5、代理模式

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

1、静态代理

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

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

缺点:

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

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

2、动态代理

1Jdk动态代理

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

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()放法 ) 

posted @ 2021-02-07 19:38  majingyun  阅读(126)  评论(0编辑  收藏  举报