Java经典设计模式详解

  • 一、设计原则
  • 二、分类
      • 1. 创建型模式–>对象怎么来
        • 解释
        • 分类
      • 2. 结构型模式–>对象和谁有关
        • 解释
        • 分类
      • 3. 行为型模式–>对象与对象在干嘛
        • 解释
        • 分类
  • 单例模式
      • 特点
      • 关键:
      • 应用场景
      • 优点
      • 缺点
    • 三种实现方式
      • 1. 懒汉模式、线程不安全
        • 特点:
      • 2. 懒汉模式,线程安全
        • 特点:
        • 优点:
        • 缺点:
      • 3. 饿汉模式
        • 特点:
        • 优点:
        • 缺点:
      • 4. 双重校验锁(doubled-checked locking)
        • 特点:
        • 优点:
  • 工厂模式
      • 作用:
      • 案例
    • 简单工厂模式
      • 特点
      • 创建步骤
      • 方法二:利用反射Class.forName(clz.getName()).newInstance()实现简单工厂模式
    • 工厂方法模式
      • 理解
      • 特点
    • - 是一个产品类的实例化延迟到其具体工厂子类
      • 实例
    • 抽象工厂模式
      • 理解:
      • 案例
      • 特点
      • 缺点
      • 实例
  • 观察者模式
    • 定义
    • 角色
    • 实例
        • 步骤
  • 代理模式
    • 1. 静态代理模式
      • 使用:
      • 特点:
      • 案例:
    • 2. 动态代理模式—-JDK中用的代理模式
      • newProxyInstance方法
      • 案例
    • Cglib代理(子类代理)
      • 实例:

一、设计原则

  1. 开闭原则:实现热插拔,提高扩展性。
  2. 里氏代换原则:实现抽象的规范,实现子父类互相替换;
  3. 依赖倒转原则:针对接口编程,实现开闭原则的基础;
  4. 接口隔离原则:降低耦合度,接口单独设计,互相隔离;
  5. 迪米特法则,又称不知道原则:功能模块尽量独立;
  6. 合成复用原则:尽量使用聚合,组合,而不是继承;

二、分类

1. 创建型模式–>对象怎么来

解释

解释:在创建对象的同时隐藏创建逻辑,而不是使用new运算符直接实例化对象,使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活

分类

  1. 工厂模式
  2. 抽象工厂模式
  3. 单例模式
  4. 建造模式
  5. 原型模式

2. 结构型模式–>对象和谁有关

解释

解释:关注类和对象的组合,继承的概念被用来组合接口各定义组合对象获得新功能

分类

  1. 适配器模式(Adapter Pattern)
  2. 桥接模式(Bridge Pattern)
  3. 过滤器模式(Filter、Criteria Pattern)
  4. 组合模式(Composite Pattern)
  5. 装饰器模式(Decorator Pattern)
  6. 外观模式(Facade Pattern)
  7. 享元模式(Flyweight Pattern)
  8. 代理模式(Proxy Pattern)

3. 行为型模式–>对象与对象在干嘛

解释

解释:关注对象间的通信

分类

责任链模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
解释器模式(Interpreter Pattern)
迭代器模式(Iterator Pattern)
中介者模式(Mediator Pattern)
备忘录模式(Memento Pattern)
观察者模式(Observer Pattern)
状态模式(State Pattern)
空对象模式(Null Object Pattern)
策略模式(Strategy Pattern)
模板模式(Template Pattern)
访问者模式(Visitor Pattern


单例模式

特点

  • 设计一个单一的类,该类负责创建自己的对象(必须自己创建自己),同时确保该类只有一个对象
  • 该类提供了一个访问它的对象的全局访问点

关键:

  • 构造函数私有
  • 创建对象时判断系统中是否有该类的对象,如果有则返回,没有则创建

应用场景

  • Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
  • 一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。

优点

  • 内存中只有一个实例,减少了内存开销,尤其是频繁创建和销毁实例的情况
  • 避免对资源的多重占用造成的错误(比如写文件操作)

缺点

  • 没有接口,不能继承

三种实现方式

1. 懒汉模式、线程不安全

特点:

懒初始化,不是线程安全的

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  

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

2. 懒汉模式,线程安全

特点:

懒初始化,线程安全、效率很低

优点:

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

缺点:

必须加锁synchronized才能保证单例,加锁会影响效率(任时刻,只能有一个线程可以调用这个方法,其余的会排队等待。)

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
} 

3. 饿汉模式

特点:

不是懒初始化,线程安全,但容易产生垃圾对象

优点:

没有加锁,效率高

缺点:

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

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

4. 双重校验锁(doubled-checked locking)

特点:

  • JDK1.5起
  • 懒初始化,线程安全

优点:

  • 懒汉模式对其整个getInstance()方法加锁不高效,双重检验锁在同步块外检查一次null,然后再在同步块内检查一次。
public class Singleton {  
    private volatile static Singleton instance;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (instance == null) {  
        synchronized (Singleton.class) {  
        if (instance == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}  

工厂模式

作用:

  • 松耦合
  • 为创建对象提供过渡接口,将创建对象的具体过程隔离起来

案例

例子:工业革命前,如果一个客户想要一台车,必须自己创造,然后拿来用;工业革命后,用户不需要创建宝马车,工厂完成创建车的过程,且工厂有多个车间,可以根据用户的需求创建不同型号的车。

简单工厂模式

特点

  • 无抽象工厂类,只有具体工厂
  • 扩展性差,弱项增加一种产品,需要新增一个具体产品类和修改工厂类的方法

创建步骤

  1. 创建一个抽象产品接口
  2. 创建实现接口的具体产品类
  3. 创建一个工厂类,根据给定信息生成特定的产品类对象
步骤 1 创建一个接口。
//Shape.java
public interface Shape {
   void draw();
}

步骤 2 创建实现接口的实体类。
//Circle.java
public class Circle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}
//Rectangle.java
public class Rectangle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

步骤 3 创建一个工厂,生成基于给定信息的实体类的对象。
//ShapeFactory.java
public class ShapeFactory {

   //使用 getShape 方法获取形状类型的对象
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      }
      return null;
   }
}
步骤 4
使用该工厂,通过传递类型信息来获取实体类的对象。
//FactoryPatternDemo.java
public class FactoryPatternDemo {

   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();

      //获取 Circle 的对象
      Shape shape1 = shapeFactory.getShape("CIRCLE");
      //调用 Circle 的 draw 方法
      shape1.draw();

      //获取 Rectangle 的对象
      //Shape shape2 = shapeFactory.getShape("RECTANGLE");
      //调用 Rectangle 的 draw 方法
      //shape2.draw();
   }
}

方法二:利用反射Class.forName(clz.getName()).newInstance()实现简单工厂模式

  • 抽象产品类和具体产品类与方法一相同
  • 工厂类不同

好处:
增加一种产品时不需要修改Factory中的方法

//步骤3:创建工厂类
public class ShapeFactory {
    /**
     * 传入Class实例化具体产品类
     */
    public static  T getShape(Class clz) {
        T result = null;
        try {
            result = (T) Class.forName(clz.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}
//步骤 4:
使用该工厂
//FactoryPatternDemo.java
public class FactoryPatternDemo {

   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();

      //获取 Circle 的对象
      Shape shape1 = shapeFactory.getShape(Circle.class);
      //调用 Circle 的 draw 方法
      shape1.draw();

      //获取 Rectangle 的对象
      Shape shape2 = shapeFactory.getShape(Rectangle.class);
      //调用 Rectangle 的 draw 方法
      shape2.draw();
   }
}

工厂方法模式

理解

  • 把简单工厂中具体的工厂类,划分成两层:抽象工厂类层+具体的工厂子类层。(一般->特殊)

特点

  • 不仅产品需要抽象,工厂也需要抽象

- 是一个产品类的实例化延迟到其具体工厂子类

实例

工厂模式
1. 创建一个抽象产品类,Shape接口
2. 创建实现接口的实体类(具体产品)
3. 创建一个抽象工厂类,
4. 创建具体的工厂类,根据给定信息生成特定的实体类对象

步骤 1
创建一个接口。
//Shape.java
public interface Shape {
   void draw();
}
步骤 2
创建实现接口的实体类。


//Circle.java
public class Circle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}
//Rectangle.java
public class Rectangle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}
步骤3
创建抽象工厂类,制定每个工厂必须生产出的指标
//AbstractFactory.java
public abstract class AbstractFactory {
   abstract Shape getShape(String shapeType) ;
}
步骤 4
创建具体工厂类,生成基于给定信息的实体类的对象。
//ShapeFactory.java
public class ShapeFactory extends AbstractFactory{

   //使用 getShape 方法获取形状类型的对象
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equals("CIRCLE")){
         return new Circle();
      } else if(shapeType.equals("RECTANGLE")){
         return new Rectangle();
      }
      return null;
   }
}

使用该工厂,通过传递类型信息来获取实体类的对象。
//FactoryPatternDemo.java
public class FactoryPatternDemo {

   public static void main(String[] args) {
      AbstractFactory shapeFactory = new ShapeFactory();

      //获取 Circle 的对象
      Shape shape1 = shapeFactory.getShape("CIRCLE");

      //调用 Circle 的 draw 方法
      shape1.draw();

      //获取 Rectangle 的对象
      Shape shape2 = shapeFactory.getShape("RECTANGLE");

      //调用 Rectangle 的 draw 方法
      shape2.draw();

   }
}

抽象工厂模式

理解:

  • 多个抽象产品类(Shape,Color),每个抽象产品类可以派生出多个具体产品类
  • 一个抽象工厂类,可以派生出多个具体工厂类
  • 每个具体工厂类可以创建多个具体产品类实例

案例

  • 抽象工厂模式每一个具体的工厂生产一个产品族,比如:Intel的工厂生产Intel的主板和Intel的芯片,AMD的工厂生产AMD的主板和AMD的芯片;而工厂方法模式是生产同一产品等级结构的产品,不如Intel主板工厂只生产Intel主板,AMD主板工厂只生产AMD主板
  • 案例一:
  • 工厂生产空调和发动机,不同型号的车辆需要不同类型的空调和发动机配置,所以抽象工厂类下面有两个具体的工厂,分别造发动机和空调,每一辆车的空调和发动机不同型号组合需要空调工厂的具体车间和发动机工厂的具体车间组合。
  • 案例二:
  • 所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。

特点

当类中的产品构成了不同等级的==产品族==,就使用抽象工厂模式

缺点

  • 产品族的扩展费力,如果产品族中需要增加一个新的产品类,那么所有的工厂类都需要修改
  • 对于每一个具体工厂类,产品族里的每种产品只能使用其中一个

实例

抽象工厂模式

  1. 创建一个抽象产品接口–形状
  2. 创建实现接口的具体类
  3. 创建另一个抽象产品接口-颜色
  4. 创建实现接口的具体类
  5. 创建抽象工厂类来获取抽象产品
  6. 创建继承了抽象工厂的具体工厂类,基于给定的信息生成具体的实例对象
步骤 1
为形状创建一个接口。
//Shape.java
public interface Shape {
   void draw();
}

步骤 2
创建实现接口的实体类。
//Rectangle.java
public class Rectangle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

//Circle.java
public class Circle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

步骤 3
为颜色创建一个接口。
//Color.java
public interface Color {
   void fill();
}

步骤4
创建实现接口的实体类。
//Red.java
public class Red implements Color {

   @Override
   public void fill() {
      System.out.println("Inside Red::fill() method.");
   }
}
//Green.java
public class Green implements Color {

   @Override
   public void fill() {
      System.out.println("Inside Green::fill() method.");
   }
}

步骤 5
创建抽象工厂类,制定每个工厂必须生产出两个指标:颜色和类型(发动机和空调)。
AbstractFactory.java
public abstract class AbstractFactory {
   abstract Color getColor();
   abstract Shape getShape() ;
}

步骤 6
具体工厂A类:红色圆形
//FactoryA.java
public class FactoryA extends AbstractFactory {
    //一个具体工厂类创建了两个具体产品类
   @Override
   public Color getColor(){
      return new Red();
   }
   @Override
   public Shape getShape(){
      return new Circle();
   }
}
具体工厂B类:绿色矩形
//FactoryB.java
public class FactoryA extends AbstractFactory {

   @Override
   public Color getColor(){
      return new Green();
   }
   @Override
   public Shape getShape(){
      return new Rectangle();
   }
}


步骤 8
AbstractFactoryPatternDemo.java
public class AbstractFactoryPatternDemo {
   public static void main(String[] args) {

      AbstractFactory aFactory = new FactoryA();
      aFactory.getShape().draw();
      aFactory.getColor().fill();

      AbstractFactory bFactory = new FactoryB();
      bFactory.getShape().draw();
      bFactory.getColor().fill();
   }
}

观察者模式

定义

在对象之坚定了一一对多的依赖,当一个对象改变状态(被观察者),依赖它的对象(观察者)就会收到通知并自动更新

角色

  • 抽象被观察者:一般用一个抽象类或者接口实现。把所有对观察者对象的引用都保存在一个集合中,每个被观察者可以有人以数量的观察者,抽象被观察者提供一个借口,可以增加和删除观察者角色
  • 抽象观察者:为所有的具体观察者定义一个接口,在得到被观察者通知时更新自己
  • 具体被观察者:具体的被观察者,在被观察者的内部状态改变时,向所有登记过的观察者发出通知
  • 具体观察者:实现抽象观察者的更新接口

实例

  • 微信公众号(被观察者)向订阅的用户(注册的观察者)发送通知

步骤

  1. 定义一个抽象被观察者接口
  2. 定义一个抽象观察者接口
  3. 具体被观察者,实现抽象被观察者接口的三个方法:注册新观察者;移除观察者;通知观察者,同时一个List保存注册的观察者
  4. 定义具体的观察者
1、定义一个抽象被观察者接口

复制代码
package com.jstao.observer;

/***
 * 抽象被观察者接口
 * 声明了添加、删除、通知观察者方法
 * @author jstao
 *
 */
public interface Observerable {

    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObserver();

}


 2、定义一个抽象观察者接口


package com.jstao.observer;

/***
 * 抽象观察者
 * 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。
 * @author jstao
 *
 */
public interface Observer {
    public void update(String message);
}
复制代码
3、定义被观察者,实现了Observerable接口,对Observerable接口的三个方法进行了具体实现,同时有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合即可。

复制代码
package com.jstao.observer;

import java.util.ArrayList;
import java.util.List;

/**
 * 被观察者,也就是微信公众号服务
 * 实现了Observerable接口,对Observerable接口的三个方法进行了具体实现
 * @author jstao
 *
 */
public class WechatServer implements Observerable {

    //注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程
    private List list;
    private String message;

    public WechatServer() {
        list = new ArrayList();
    }

    @Override
    public void registerObserver(Observer o) {

        list.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        if(!list.isEmpty())
            list.remove(o);
    }

    //遍历
    @Override
    public void notifyObserver() {
        for(int i = 0; i < list.size(); i++) {
            Observer oserver = list.get(i);
            oserver.update(message);
        }
    }

    public void setInfomation(String s) {
        this.message = s;
        System.out.println("微信服务更新消息: " + s);
        //消息更新,通知所有观察者
        notifyObserver();
    }

}
复制代码
4、定义具体观察者,微信公众号的具体观察者为用户User

复制代码
package com.jstao.observer;

/**
 * 观察者
 * 实现了update方法
 * @author jstao
 *
 */
public class User implements Observer {

    private String name;
    private String message;

    public User(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        this.message = message;
        read();
    }

    public void read() {
        System.out.println(name + " 收到推送消息: " + message);
    }

}
复制代码
5、编写一个测试类

首先注册了三个用户,ZhangSan、LiSi、WangWu。公众号发布了一条消息"PHP是世界上最好用的语言!",三个用户都收到了消息。

用户ZhangSan看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其他用户

还是正常能收到推送消息。

复制代码
package com.jstao.observer;

public class Test {

    public static void main(String[] args) {
        WechatServer server = new WechatServer();

        Observer userZhang = new User("ZhangSan");
        Observer userLi = new User("LiSi");
        Observer userWang = new User("WangWu");

        server.registerObserver(userZhang);
        server.registerObserver(userLi);
        server.registerObserver(userWang);
        server.setInfomation("PHP是世界上最好用的语言!");

        System.out.println("----------------------------------------------");
        server.removeObserver(userZhang);
        server.setInfomation("JAVA是世界上最好用的语言!");

    }
}

代理模式

含义:提供了对目标对象另外的访问方式:通过代理对象访问目标对象
在Spring的AOP编程中:
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用Cglib代理

代理模式

关键点:代理对象与目标对象,代理对象是对目标对象的扩展,并且会调用目标对象

1. 静态代理模式

静态:程序运行前就编译好的,不是由程序动态产生代理类

使用:

静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象必须实现==相同的接口或者继承相同的父类==,然后通过相同的方法来调用目标对象的方法

特点:

  1. 优点:
    • 不修改目标对象的功能,对目标对象进行扩展
  2. 缺点
    • 代理对象需要实现与目标对象相同的接口,所以会有很多代理类,类太多
    • 一旦接口增加方法,目标对象和代理对象都需要维护

案例:

保存动作,定义一个保存动作的接口IUserDao.java,目标对象(Target)实现了这个接口,如果使用静态代理,需要在代理对象(ProxyUserDao)中也实现这个接口,调用的时候通过调用代理对象的方法来调用目标对象

/**
 * 接口
 */
public interface IUserDao {

    void save();
}
/**
 * 目标对象
 */
public class Target implements IUserDao {
    public void save() {
        System.out.println("----已经保存数据!----");
    }
}
/**
 * 代理对象,静态代理----实现接口式
 */
public class ProxyUserDao implements IUserDao{
    //接收保存目标对象
    private IUserDao target;
    public ProxyUserDao(IUserDao target){
        this.target=target;
    }

    public void save() {
        System.out.println("开始事务...");//对目标对象该方法的扩充部分
        target.save();//执行目标对象的方法
        System.out.println("提交事务...");
    }
}
/**
 * 测试类---实现接口式
 */
public class App {
    public static void main(String[] args) {
        //目标对象
        Target target = new Target();

        //代理对象,把目标对象传给代理对象,建立代理关系(代理对象的构造喊数有参数的)
        ProxyUserDao proxy = new ProxyUserDao(target);

        proxy.save();//执行的是代理的方法
    }
}

继承式

public class ProxyUserDao extenda Target{
    //省略构造方法,因为构造函数无参

    public void save() {
        System.out.println("开始事务...");//对目标对象该方法的扩充部分
        super.save();//执行目标对象的方法
        System.out.println("提交事务...");
    }
}
/**
 * 测试类
 */
public class App {
    public static void main(String[] args) {
    //不需要将目标对象传给代理对象,因为代理对象的构造函数是继承的Target无参的
        ProxyUserDao proxy = new ProxyUserDao();

        proxy.save();//执行的是代理的方法
    }
}

2. 动态代理模式—-JDK中用的代理模式

含义:代理对象不需要实现接口,代理对象的生成是利用JDK中的API,动态在内存中构建代理对象

newProxyInstance方法

  1. JDK中生成代理对象的API:java.lang.reflect.Proxy包下的newProxyInstance方法
    static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h )
  2. 静态方法
  3. 参数列表:
    • ClassLoader loader,:指定当前目标对象使用类加载器(Object.getClass().getClassLoader(),),获取加载器的方法是固定的
    • Class

案例

/**
 * 接口
 */
public interface IUserDao {

    void save();
}
/**
 * 目标对象
 */
public class Target implements IUserDao {
    public void save() {
        System.out.println("----已经保存数据!----");
    }
}

/**
 * 创建动态代理对象
 * 动态代理不需要实现接口,但是需要指定接口类型
 */
public class ProxyFactory{

    //维护一个目标对象
    private Object target;
    public ProxyFactory(Object target){
        this.target=target;
    }

   //给目标对象生成代理对象
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                //创建一个实现InvocationHandler接口的类,它必须实现invoke()方法
                new InvocationHandler() {
                    @Override--匿名内部类
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("开始事务2");
                        //执行目标对象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("提交事务2");
                        return returnValue;
                    }
                }
        );
    }

}

/**
 * 测试类
 */
public class App {
    public static void main(String[] args) {
        // 目标对象
        IUserDao target = new UserDao();
        // 【原始的类型 class cn.itcast.b_dynamic.UserDao】
        System.out.println(target.getClass());

        // 给目标对象,创建代理对象
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
        // class $Proxy0   内存中动态生成的代理对象
        System.out.println(proxy.getClass());

        // 执行方法   【代理对象】
        proxy.save();
    }
}

Cglib代理(子类代理)

背景:上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理

含义:在内存中构建一个子类对象从而实现对目标对象功能的扩展.

特点:
- 若想要代理没有实现接口的类,可以用Cglib实现
- Cglib是一个代码生成包,可以在运行期扩展java类与实现java接口,被很多AOP框架使用
- Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.

步骤:
1. 需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可.
2. 引入功能包后,就可以在内存中动态构建子类
3. 代理的类不能为final,否则报错(final修饰的方法不可被继承)
4. 目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.

实例:

/**
 * 目标对象,没有实现任何接口
 */
public class UserDao {

    public void save() {
        System.out.println("----已经保存数据!----");
    }
}
/**
 * Cglib子类代理工厂
 * 对UserDao在内存中动态构建一个子类对象
 */
public class ProxyFactory implements MethodInterceptor{
    //维护目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();

    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开始事务...");

        //执行目标对象的方法
        Object returnValue = method.invoke(target, args);

        System.out.println("提交事务...");

        return returnValue;
    }
}
/**
 * 测试类
 */
public class App {

    @Test
    public void test(){
        //目标对象
        UserDao target = new UserDao();

        //代理对象
        UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();

        //执行代理对象的方法
        proxy.save();
    }
}

你可能感兴趣的:(Java基础,java,设计模式)