GoF23种设计模式


23种设计模式

设计模式的分类 总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

OOP七大原则

开闭原则:对扩展开放,对修改关闭

里氏替换原则:继承必须确保超累所拥有的性质在子类中任然成立(尽量不重写父类的方法)

依赖倒置原则:要面向接口编程,不要面向实现编程

单一职责原则:控制类的粒度大小、将对象解耦、提高其内聚性

接口隔离原则:要为各个类创建他们需要的专用接口

迪米特法则:只与你的直接朋友交谈,不跟“陌生人”说话

合成复用原则:尽量先试用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现


创建型模式

单例模式:

            一个类有且仅有一个实例,并且自行实例化向整个系统提供。

饿汉式 DCL懒汉式,深究!

饿汉式

单例模式首先将构造器私有

 // 饿汉式单例
 public class Hungry {
 ?
     //可能会浪费空间
     private byte[] date1 = new byte[1024*1024];
     private byte[] date2 = new byte[1024*1024];
     private byte[] date3 = new byte[1024*1024];
     private byte[] date4 = new byte[1024*1024];
 //私有构造器
     private Hungry(){
 ?
     }
 ?
     private final static Hungry HUNGRY = new Hungry();
 ?
     public static Hungry getInstance(){
         return HUNGRY;
     }
 }

 

DCL懒汉式

 //懒汉式单例
 //道高一尺,魔高一丈!
 public class LazyMan {
 ?
     private static boolean qinjiang = false;
 ?
     //构造器私有
     private LazyMan(){
         synchronized (LazyMan.class){
             if (qinjiang == false){
                 qinjiang = true;
             }else {
                 throw new RuntimeException("不要试图使用反射破坏异常");
             }
         }
     }
 ?
     private volatile static LazyMan lazyMan;    //volatile 避免指令重排,保证线程间的可见性
 ?
     //双重检测锁模式的 懒汉式单例 DCL懒汉式
     public static LazyMan getInstance() {
         if (lazyMan == null) {
             synchronized (LazyMan.class){
 ?
                 if (lazyMan == null) {
                     lazyMan = new LazyMan();//不是一个原子性操作
                 }
             }
         }
         return lazyMan;
 ?
     }
 ?
     public static void main(String[] args) throws Exception {
        // LazyMan instance = LazyMan.getInstance();
         Field qinjiang = LazyMan.class.getDeclaredField("qinjiang");
         qinjiang.setAccessible(true);
 ?
         Constructor declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
         declaredConstructor.setAccessible(true);
         LazyMan instance = declaredConstructor.newInstance();
 ?
         qinjiang.set(instance,false);
 ?
         LazyMan instance2 = declaredConstructor.newInstance();
 ?
 ?
         System.out.println(instance);
         System.out.println(instance2);
 ?
     }
 ?
 ?
 ?
 ?
 ?
 }
 /**
  * 1.分配内存空间
  * 2.执行构造方法,初始化对象
  * 3.把这个对象指向这个空间
  *
  * 123
  * 132 A
  *      B // 此时还没有完成构造
  */

静态内部类

 //静态内部类
 public class Holder {
 ?
     //构造器私有
     private Holder(){
 ?
     }
 ?
     public static Holder getInstance(){
         return InnerClass.HOLDER;
     }
 ?
     public static class InnerClass{
         private static final Holder HOLDER = new Holder();
     }
 }

枚举:Enum

单例不安全,反射

 //enum 是什么?  本身也是一个class类
 public enum EnumSingle {
 ?
     INSTANCE;
 ?
     public EnumSingle getInstance(){
         return INSTANCE;
     }
 ?
 }
 class Test{
     public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
         EnumSingle instance = EnumSingle.INSTANCE;
 ?
 ?
 ?
         Constructor declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
         declaredConstructor.setAccessible(true);
         EnumSingle instance1 = declaredConstructor.newInstance();
 ?
        //  NoSuchMethodException: com.kuang.single.EnumSingle.()
         System.out.println(instance);
         System.out.println(instance1);
 ?
     }
 }

枚举最终反编译:

javap -p 文件名

下载反编译工具将class文件反编译

工厂模式

简单工厂模式

:简单工厂模式是属于创建型模式,又叫做静态工厂方法模式

例如:(直接看代码)

先写一个接口

 public interface Car {
     void name();
 }

定义他的工厂类

 //静态工厂模式
 //增加一个新的产品,如果不修改代码,做不到!
 ?
 //开闭原则
 public class CarFactory {
 ?
     //方法一:
     public static Car getCar(String car){
         if (car.equals("五菱")){
             return new WuLing();
         }else if (car.equals("特斯拉")){
             return new Tesla();
         }else {
             return null;
         }
     }
 ?
     //方法二:
     public static Car getWuLing(){
         return new WuLing();
     }
     public static Car getTesla(){
         return new Tesla();
     }
 }

汽车的品牌实现接口

 public class Dazhong implements Car{
     @Override
     public void name() {
         System.out.println("大众!");
     }
 }
 public class Tesla implements Car{
     @Override
     public void name() {
         System.out.println("特斯拉!");
     }
 }
 public class WuLing implements Car{
     @Override
     public void name() {
         System.out.println("五菱宏光!");
     }
 }

消费者买车

 public class Consumer {
     public static void main(String[] args) {
         //接口,所有的实现类!工厂
         //Car car = new WuLing();
         //Car car2 = new Tesla();
 ?
         //2.使用工厂类实现
 ?
         Car car = CarFactory.getCar("五菱");
         Car car2 = CarFactory.getCar("特斯拉");
 ?
         car.name();
         car2.name();
     }
 }

工厂方法模式

:是一种常用的类创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。

定义接口

 public interface Car {
     void name();
 }

定义车工厂

 //工厂方法模式
 public interface CarFactory {
     Car getCar();
 }

车品牌工厂 :实现车工厂接口

 public class MoBaiFactory implements CarFactory{
     @Override
     public Car getCar() {
         return new MoBai();
     }
 }
 public class TeslaFactory implements CarFactory{
     @Override
     public Car getCar() {
         return new Tesla();
     }
 }
 public class WuLingFactory implements CarFactory{
     @Override
     public Car getCar() {
         return new WuLing();
     }
 }

汽车:实现Car接口

 public class MoBai implements Car{
     @Override
     public void name() {
         System.out.println("摩拜单车!");
     }
 }
 public class Tesla implements Car {
     @Override
     public void name() {
         System.out.println("特斯拉!");
     }
 }
 public class WuLing implements Car {
     @Override
     public void name() {
         System.out.println("五菱宏光!");
     }
 }

消费者可以直接去车工厂提取车,不需要考虑其他

 public class Consumer {
     public static void main(String[] args) {
         Car car = new WuLingFactory().getCar();
         Car car2 = new TeslaFactory().getCar();
 ?
         car.name();
         car2.name();
         Car car3 = new MoBaiFactory().getCar();
         car3.name();
     }
 }

抽象工厂模式

:抽象工厂是指当有多个抽象角色时使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象。

 

 public interface IProductFactory {
 //产品工厂 、生产手机与路由器
     //生产手机
     IphoneProduct  iphoneProduct();
 ?
     //生产路由器
     IRouterProduct routerProduct();
 }
 //手机产品接口
 public interface IphoneProduct {
 ?
     void start();
     void shutdown();
     void callup();
     void sendSMS();
 ?
 }
 public interface IRouterProduct {
 //路由器产品接口
     void start();
     void shutdown();
     void openWifi();
     void setting();
 ?
 }

不同手机工厂:需要实现产品接口,并且重写方法

 public class HuaweiFactory implements IProductFactory{
     @Override
     public IphoneProduct iphoneProduct() {
         return new HuaweiIphone();
     }
 ?
     @Override
     public IRouterProduct routerProduct() {
         return new HuaweiIRouter();
     }
 }
 public class XiaomiFactory implements IProductFactory{
     @Override
     public IphoneProduct iphoneProduct() {
         return new XiaomiPhone();
     }
 ?
     @Override
     public IRouterProduct routerProduct() {
         return new XiaomiIRouter();
     }
 }

不同手机实现手机接口

 //华为手机
 public class HuaweiIphone implements IphoneProduct{
     @Override
     public void start() {
         System.out.println("开启华为手机");
     }
 ?
     @Override
     public void shutdown() {
         System.out.println("关闭华为手机");
     }
 ?
     @Override
     public void callup() {
         System.out.println("华为手机打电话");
     }
 ?
     @Override
     public void sendSMS() {
         System.out.println("华为发短信");
     }
 }
 //小米手机
 public class XiaomiPhone implements IphoneProduct{
     @Override
     public void start() {
         System.out.println("开启小米手机");
     }
 ?
     @Override
     public void shutdown() {
         System.out.println("小米手机关机");
     }
 ?
     @Override
     public void callup() {
         System.out.println("小米打电话");
     }
 ?
     @Override
     public void sendSMS() {
         System.out.println("小米发短信");
     }
 }
 //华为路由器
 public class HuaweiIRouter implements IRouterProduct{
     @Override
     public void start() {
         System.out.println("启动华为路由器");
     }
 ?
     @Override
     public void shutdown() {
         System.out.println("关闭华为路由器");
     }
 ?
     @Override
     public void openWifi() {
         System.out.println("打开华为wifi");
     }
 ?
     @Override
     public void setting() {
         System.out.println("华为设置");
     }
 }
 //小米路由器
 public class XiaomiIRouter implements IRouterProduct{
     @Override
     public void start() {
         System.out.println("启动小米路由器");
     }
 ?
     @Override
     public void shutdown() {
         System.out.println("关闭小米路由器");
     }
 ?
     @Override
     public void openWifi() {
         System.out.println("打开小米wifi");
     }
 ?
     @Override
     public void setting() {
         System.out.println("小米设置");
     }
 }

建造者模式

( Builder ):建造者模式是设计模式的一种,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

例:工地建房子

 //抽象的建造者:方法
 public abstract class Builder {
 ?
     //步骤:A->B->C->D
     abstract void buildA();//地基
     abstract void buildB();//钢筋工程
     abstract void buildC();//铺电线
     abstract void buildD();//粉刷
 ?
     //完工:得到产品
     abstract Product getProduct();
 }
 //产品:房子
 public class Product {
     private String buildA;
     private String buildB;
     private String buildC;
     private String buildD;
 ?
     public String getBuildA() {
         return buildA;
     }
 ?
     public void setBuildA(String buildA) {
         this.buildA = buildA;
     }
 ?
     public String getBuildB() {
         return buildB;
     }
 ?
     public void setBuildB(String buildB) {
         this.buildB = buildB;
     }
 ?
     public String getBuildC() {
         return buildC;
     }
 ?
     public void setBuildC(String buildC) {
         this.buildC = buildC;
     }
 ?
     public String getBuildD() {
         return buildD;
     }
 ?
     public void setBuildD(String buildD) {
         this.buildD = buildD;
     }
 ?
     @Override
     public String toString() {
         return "Product{" +
                 "buildA='" + buildA + '\'' +
                 ", buildB='" + buildB + '\'' +
                 ", buildC='" + buildC + '\'' +
                 ", buildD='" + buildD + '\'' +
                 '}';
     }
 }

定义一个工人类

 public class Worker extends Builder{
 ?
     private Product product;
 ?
     public Worker() {
         product = new Product();
     }
 ?
     @Override
     void buildA() {
         product.setBuildA("地基");
         System.out.println("地基");
     }
 ?
     @Override
     void buildB() {
         product.setBuildB("钢筋工程");
         System.out.println("钢筋工程");
     }
 ?
     @Override
     void buildC() {
         product.setBuildC("铺电线");
         System.out.println("铺电线");
     }
 ?
     @Override
     void buildD() {
         product.setBuildD("粉刷");
         System.out.println("粉刷");
     }
 ?
     @Override
     Product getProduct() {
         return product;
     }
 }

定义指挥者:负责指挥工人

 //指挥:核心。负责指挥构建一个工程,工程如何构建,由他指挥
 public class Director {
     public Product build(Builder builder){
 ?
         //指挥工人按照顺序建房子
         builder.buildA();
         builder.buildB();
         builder.buildC();
         builder.buildD();
 ?
         return builder.getProduct();
     }
 ?
 }

测试:

 public class Test {
     public static void main(String[] args) {
         //指挥
         Director director = new Director();
 ?
         //指挥  具体的工人完成  产品
         Product build = director.build(new Worker());
         System.out.println(build.toString());
     }
 }

 public abstract class Builder {
 ?
 ?
     abstract Builder buildeA(String msg);//汉堡
     abstract Builder buildeB(String msg);//可乐
     abstract Builder buildeC(String msg);//薯条
     abstract Builder buildeD(String msg);//甜点
 ?
     abstract Product getProduct();
 }

套餐

 //产品:套餐
 public class Product {
 ?
     private String BuildA="汉堡";
     private String BuildB="可乐";
     private String BuildC="薯条";
     private String BuildD="甜点";
 ?
     public String getBuildA() {
         return BuildA;
     }
 ?
     public void setBuildA(String buildA) {
         BuildA = buildA;
     }
 ?
     public String getBuildB() {
         return BuildB;
     }
 ?
     public void setBuildB(String buildB) {
         BuildB = buildB;
     }
 ?
     public String getBuildC() {
         return BuildC;
     }
 ?
     public void setBuildC(String buildC) {
         BuildC = buildC;
     }
 ?
     public String getBuildD() {
         return BuildD;
     }
 ?
     public void setBuildD(String buildD) {
         BuildD = buildD;
     }
 ?
     @Override
     public String toString() {
         return "Product{" +
                 "BuildA='" + BuildA + '\'' +
                 ", BuildB='" + BuildB + '\'' +
                 ", BuildC='" + BuildC + '\'' +
                 ", BuildD='" + BuildD + '\'' +
                 '}';
     }
 }
 //具体的建造者
 public class Worker extends Builder{
 ?
     private Product product;
 ?
     public Worker() {
         product = new Product();
     }
 ?
     @Override
     Builder buildeA(String msg) {
         product.setBuildA(msg);
         return this;
     }
 ?
     @Override
     Builder buildeB(String msg) {
         product.setBuildB(msg);
         return this;
     }
 ?
     @Override
     Builder buildeC(String msg) {
         product.setBuildC(msg);
         return this;
     }
 ?
     @Override
     Builder buildeD(String msg) {
         product.setBuildD(msg);
         return this;
     }
 ?
     @Override
     Product getProduct() {
         return product;
     }
 ?
 ?
 }

用户可以自己搭配选择

 public class Test {
     public static void main(String[] args) {
 ?
         //服务员
         Worker worker = new Worker();
 ?
         //链式编程  : 在原来的基础上,可以自由组合了,如果不组合,也有默认的套餐
         Product product = worker.buildeA("全家桶").buildeB("雪碧")
                 .getProduct();
         System.out.println(product.toString());
     }
 }

原型模式

:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

复制拷贝: 第一个方案复制的会跟之前的共用一个时间

 /*
 1.实现一个接口     Cloneable
 2.重写一个方法     clone()
 */
 ?
 ?
 //Video
 public class Video implements Cloneable{
 ?
     private String name;
     private Date createTime;
 ?
     @Override
     protected Object clone() throws CloneNotSupportedException {
         return super.clone();
     }
 ?
     public Video() {
     }
 ?
     public Video(String name, Date createTime) {
         this.name = name;
         this.createTime = createTime;
     }
 ?
     public String getName() {
         return name;
     }
 ?
     public void setName(String name) {
         this.name = name;
     }
 ?
     public Date getCreateTime() {
         return createTime;
     }
 ?
     public void setCreateTime(Date createTime) {
         this.createTime = createTime;
     }
 ?
     @Override
     public String toString() {
         return "Video{" +
                 "name='" + name + '\'' +
                 ", createTime=" + createTime +
                 '}';
     }
 }

 

 

 public class Bilibili {
 ?
     public static void main(String[] args) throws CloneNotSupportedException {
         //原型对象  v1
 ?
         Date date = new Date();
         Video v1 = new Video("狂神说JAVA", date);
         System.out.println("v1=>"+v1);
         System.out.println("v1=>hash"+v1.hashCode());
 ?
         //v1  克隆  v2
         //Video v2 = new Video("狂神说JAVA", date);
         Video v2 = (Video) v1.clone();
         System.out.println("v2=>"+v2);
         System.out.println("v2=>hash"+v2.hashCode());
 ?
     }
 }

第二个在修改时间的情况下会分隔开

 /*
 1.实现一个接口     Cloneable
 2.重写一个方法     clone()
 */
 ?
 ?
 //Video
 public class Video implements Cloneable{
 ?
     private String name;
     private Date createTime;
 ?
     @Override
     protected Object clone() throws CloneNotSupportedException {
 ?
         Object obj = super.clone();
 ?
         //实现深克隆~  序列化、反序列化
         Video v = (Video) obj;
         v.createTime = (Date)this.createTime.clone();//将这个对象的属性进行克隆
 ?
         return obj;
     }
 ?
     public Video() {
     }
 ?
     public Video(String name, Date createTime) {
         this.name = name;
         this.createTime = createTime;
     }
 ?
     public String getName() {
         return name;
     }
 ?
     public void setName(String name) {
         this.name = name;
     }
 ?
     public Date getCreateTime() {
         return createTime;
     }
 ?
     public void setCreateTime(Date createTime) {
         this.createTime = createTime;
     }
 ?
     @Override
     public String toString() {
         return "Video{" +
                 "name='" + name + '\'' +
                 ", createTime=" + createTime +
                 '}';
     }
 }

 

 

 //Spring Bean:单例模式,原型模式~
 // 原型模式 + 工厂模式 ==> new <==> 原型模式
 ?
 public class Bilibili {
 ?
     public static void main(String[] args) throws CloneNotSupportedException {
 ?
         //原型对象  v1
 ?
         Date date = new Date();
         Video v1 = new Video("狂神说JAVA", date);
         Video v2 = (Video) v1.clone();
 ?
         System.out.println("v1=>"+v1);
         System.out.println("v2=>"+v2);
         System.out.println("======================");
         date.setTime(231321312);
 ?
         System.out.println("v1=>"+v1);
         System.out.println("v2=>"+v2);
 ?
      /*
         //原型对象  v1
 ?
         Date date = new Date();
         Video v1 = new Video("狂神说JAVA", date);
         System.out.println("v1=>"+v1);
         System.out.println("v1=>hash"+v1.hashCode());
 ?
         //v1  克隆  v2
         //Video v2 = new Video("狂神说JAVA", date);
         Video v2 = (Video) v1.clone();
         System.out.println("v2=>"+v2);
         System.out.println("v2=>hash"+v2.hashCode());
     */
     }
 }

结构型模式

适配器模式

:是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。

image-20220116131748349

 //接口转换器的抽象实现
 public interface NetToUsb {
 ?
     //作用:处理请求,网线=>usb
     public void handleRequest();
 }
//要被适配的类    :网线
public class Adaptee {

    public void request(){

        System.out.println("连接网线上网");
    }
}
//1.继承  (类适配器,单继承)----
//2.组合  (对象适配器,常用)


//真正的适配器~,需要连接USB,连接网线~
public class Adapter extends Adaptee implements NetToUsb{

    @Override
    public void handleRequest() {
        super.request();//可以上网了~
    }
}
//1.继承  (类适配器,单继承)
//2.组合  (对象适配器,常用)------


//真正的适配器~,需要连接USB,连接网线~
public class Adapter2  implements NetToUsb{

    private Adaptee adaptee;

    public Adapter2(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void handleRequest() {
        adaptee.request();//可以上网了~
    }
}
//客户端类:想上网,插不上网线~
public class Computer {

    //我们的电脑需要连接上转接器才可以上网
    public void net(NetToUsb adapter) {
        //上网的具体实现~,找一个转接头
        adapter.handleRequest();
    }


    public static void main(String[] args) {
        //电脑,网线,适配器~
        Computer computer = new Computer();//电脑
        Adaptee adaptee = new Adaptee();//网线
        Adapter2 adapter = new Adapter2(adaptee);//转接器  (比较完美的实现)
        //Adapter adapter = new Adapter();//转接器


        computer.net( adapter);
    }
}

桥接模式

:是将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(interface)模式。

结构图:

image-20220116141205519

//品牌
public interface Brand {

    void info();

}
//苹果
public class Apple implements Brand{
    @Override
    public void info() {
        System.out.print("苹果");
    }
}
//联想
public class Lenovo implements Brand{
    @Override
    public void info() {
        System.out.print("联想");
    }
}
//抽象的电脑类
public abstract class Computer {

    //组合,品牌~
    protected Brand brand;

    public Computer(Brand brand) {
        this.brand = brand;
    }

    public void info(){
        brand.info();//自带品牌
    }
}

class Desktop extends Computer{
    public Desktop(Brand brand) {
        super(brand);
    }

    @Override
    public void info() {
        super.info();
        System.out.println("台式机");
    }
}

class Laptop extends Computer{
    public Laptop(Brand brand) {
        super(brand);
    }

    @Override
    public void info() {
        super.info();
        System.out.println("笔记本");
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        //苹果笔记本
        Computer computer = new Laptop(new Apple());
        computer.info();

        //联想台式机
        Computer computer2 = new Desktop(new Lenovo());
        computer2.info();
    }
}

结构:(同理上面的图)

image-20220116141221049


 

代理模式

为什么要学习代理模式?这就是SpringAOP的底层! 【SpringAOP 和 SpringMVC】

代理模式的分类:

  • 静态代理

  • 动态代理

image-20220116142525490

1.静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决

  • 真是角色:被代理的角色

  • 代理角色:代理真实角色,代理真实角色后一般会做一些附属操作

  • 客户:访问代理对象的人!

 

代码步骤:

1.接口

//租房
public interface Rent {

    public void rent();
}

2.真实角色

//房东
public class Landlord implements Rent{
    @Override
    public void rent() {
        System.out.println("房东要出租房子!");
    }
}

3.代理角色

public class Proxy implements Rent{

    private Landlord landlord;

    public Proxy() {
    }

    public Proxy(Landlord landlord) {
        this.landlord = landlord;
    }

    @Override
    public void rent() {
        seeHouse();
        landlord.rent();
        hetong();
        fee();
    }

    public void seeHouse(){
        System.out.println("中介带你看房");
    }

    public void fee(){
        System.out.println("收中介费");
    }

    public void hetong(){
        System.out.println("签租赁合同");
    }
}

4.客户端访问代理角色

public class Client {

    public static void main(String[] args) {
        //房东要出租房子
        Landlord landlord = new Landlord();
        //代理,中介帮房东出租房子,但是呢?代理角色一般会有一些附属操作
        Proxy proxy = new Proxy(landlord);
        //你不用面对房东,直接找中介租房子即可!
        proxy.rent();
    }

}

 

代理模式的好处:

  • 可以使真是角色的操作更加纯粹!不用去关注一些公共的业务

  • 公共的业务也就交给代理角色!实现了业务的分工!

  • 公共业务发生拓展的时候,方便集中管理!

缺点:

  • 一个真是角色就会产生一个代理角色:代码量会翻倍~ 开发效率会变低~

2.加深理解静态代理

代码:

1.接口

public interface UserService {

    public void add();
    public void delete();
    public void update();
    public void query();
}

2.实现类

//真实对象
public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void update() {
        System.out.println("修改了一个用户");
    }

    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }
    //1、改动原有的业务代码,在公司中是大忌!
}

3.代理

public class UserServiceProxy implements UserService{

    UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    @Override
    public void add() {
        log("add");
        userService.add();
    }

    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }

    @Override
    public void update() {
        log("update");
        userService.update();
    }

    @Override
    public void query() {
        log("query");
        userService.query();
    }

    //日志方法
    public void log(String msg){
        System.out.println("使用了[Debug]"+msg+"方法");
    }
}

4.客户端访问

public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();

        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserService(userService);

        proxy.add();
    }
}

image-20220116162919431

3.动态代理

  • 动态代理和静态代理角色一样

  • 动态代理的代理类是动态的,不是我们直接写好的!

  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理

    • 基于接口- - - JDK动态代理【我们在这里使用】

    • 基于类:cglib

    • Java字节码实现:javasist

需要了解两个类:Proxy:代理,InvocationHandler:调用处理程序

 

动态代理的好处:

  • 可以使真是角色的操作更加纯粹!不用去关注一些公共的业务

  • 公共的业务也就交给代理角色!实现了业务的分工!

  • 公共业务发生拓展的时候,方便集中管理!

  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务

  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可!

代码:

1.接口

//租房
public interface Rent {

    public void rent();
}

2.真实对象

//房东
public class Landlord implements Rent {
    @Override
    public void rent() {
        System.out.println("房东要出租房子!");
    }
}

3.代理

public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口
    private Rent rent;

    public void setRent(Rent rent) {
        this.rent = rent;
    }

    //生成得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //动态代理的本质,就是反射机制的实现!
        seeHouse();
        Object result = method.invoke(rent,args);
        return result;
    }

    public void seeHouse(){
        System.out.println("中介带看房子");
    }
}

4.客户端访问对象

public class Client {

    public static void main(String[] args) {
        //真实角色
        Landlord landlord = new Landlord();

        //代理角色:现在没有
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        //通过调用程序处理角色来处理我们要调用的接口对象!
        pih.setRent(landlord);
        Rent proxy = (Rent) pih.getProxy();//这里的proxy就是动态生成的,我们并没有写!
        proxy.rent();
    }
}

优化动态代理万能的方法:

public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }


    //生成得到代理类
    public Object getProxy(){//最后面的this代表实现的接口  InvocationHandler
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        log(method.getName());
        //动态代理的本质,就是反射机制的实现!
        Object result = method.invoke(target,args);
        return result;
    }

    public void log (String msg){
        System.out.println("使用了"+msg+"方法");
    }
}
public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService = new UserServiceImpl();
        //代理角色,不存在
        ProxyInvocationHandler pih = new ProxyInvocationHandler();

        pih.setTarget(userService);//设置要代理的对象
        //动态生成代理类
        UserService proxy = (UserService) pih.getProxy();
        proxy.query();
    }
}