设计模式(待更新)

OOP七大原则

开闭原则:对扩展开发,对修改关闭。
里氏替换原则: 继承必须确保超类所拥有的性质在子类中仍然成立
依赖倒置原则: 要面向接口编程,不要面向实现编程。
单一职责原则: 控制类的粒度大小、将对象解耦、提高其内聚性。
接口隔离原则: 要为各个类建立它们需要的专用接口
迪米特法则: 只与你的直接朋友交谈,不跟"陌生人”说话。
合成复用原则: 尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

单例模式

饿汉式

package com.sanjin.single;

//饿汉式单例

//饿汉,一上来就把实例加载了
public class Hungry {

    //可能会浪费空间
    private byte[] data1=new byte[1024*1024];
    private byte[] data2=new byte[1024*1024];
    private byte[] data3=new byte[1024*1024];
    private byte[] data4=new byte[1024*1024];

    //构造器私有
    private Hungry(){

    }
    //保证唯一
    private final static Hungry HUBGRY= new Hungry();

    public static Hungry getInstance(){
        return HUBGRY;
    }
}

DCL懒汉式

package com.sanjin.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

//懒汉式单例
public class LazyMan {

    private static boolean sanjin =false;

    private LazyMan(){
        synchronized (LazyMan.class){
            if (sanjin==false){
                sanjin=true;
            }else {

                throw new RuntimeException("不要试图使用反射破坏异常");
            }
        }
        System.out.println(Thread.currentThread().getName());
    }
    private volatile static LazyMan lazyMan;

    //双重检测锁模式的 懒汉式单例 DCL 懒汉式
    public static LazyMan getInstance(){
        //加锁
        if (lazyMan==null){
            synchronized (LazyMan.class){
                if (lazyMan==null){
                    lazyMan=new LazyMan();//不是原子性操作
                    /*
                    1. 分配内存空间
                    2. 执行构造方法初始化对象
                    3. 把这个对象指向这个空间

                    123
                    132
                     */
                }
            }
        }
        if (lazyMan==null){
            lazyMan=new LazyMan();
        }
        return lazyMan;
    }
    //单线程下ok

    //多线程并发

    //反射!
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        //LazyMan instance = LazyMan.getInstance();
        Field sanjin = LazyMan.class.getDeclaredField("sanjin");
        sanjin.setAccessible(true);
        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        LazyMan lazyMan = declaredConstructor.newInstance();
        sanjin.set(lazyMan,false);
        LazyMan lazyMan1 = declaredConstructor.newInstance();

        System.out.println(lazyMan==lazyMan1);

    }
}

静态内部类

package com.sanjin.single;

//静态内部类
public class Holder {
    private Holder(){

    }
    public static Holder getInstance(){
        return innerClass.HOLDER;
    }

    public static  class innerClass{
        private static final Holder HOLDER=new Holder();
    }
}

单例不安全,反射

枚举

package com.sanjin.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

//enum 是一个什么? 本身也是一个class类
public enum EnumSingle {
    INSTANCE;

    public EnumSingle getInstance(){
        return INSTANCE;
    }
}
class Test{

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        EnumSingle instance = EnumSingle.INSTANCE;
        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        declaredConstructor.setAccessible(true);

        EnumSingle enumSingle = declaredConstructor.newInstance();
        System.out.println(instance==enumSingle);

    }
}

image.png

枚举类型的最终反编译

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   EnumSingle.java

package com.sanjin.single;


public final class EnumSingle extends Enum
{

    public static EnumSingle[] values()
    {
        return (EnumSingle[])$VALUES.clone();
    }

    public static EnumSingle valueOf(String name)
    {
        return (EnumSingle)Enum.valueOf(com/sanjin/single/EnumSingle, name);
    }

    private EnumSingle(String s, int i)
    {
        super(s, i);
    }

    public EnumSingle getInstance()
    {
        return INSTANCE;
    }

    public static final EnumSingle INSTANCE;
    private static final EnumSingle $VALUES[];

    static 
    {
        INSTANCE = new EnumSingle("INSTANCE", 0);
        $VALUES = (new EnumSingle[] {
            INSTANCE
        });
    }
}

简单(静态)工厂模式

满足 :开闭原则,依赖倒置原则,迪米特法则。

核心本质
实例化对象不使用new,用工厂方法代替。
将选择实现类,创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。

简单工厂模式:
创建接口:

package model.factory.simple;

public interface Car {
    void name();
}

两个实现类

package model.factory.simple;

public class Tesla implements Car{
    @Override
    public void name() {
        System.out.println("Tesla");
    }
}

package model.factory.simple;

public class WuLing implements Car{
    @Override
    public void name() {
        System.out.println("五菱神车");
    }
}

创建工厂

package model.factory.simple;


// 静态工厂模式
// 增加新的产品,必须修改代码,这是弊端,这违背了开闭原则

public class CarFactory {
    public static Car getCar(String car){
        if (car==null||car.length()<=0){
            return null;
        }
        if (car.equals("五菱")){
            return new WuLing();
        }else if (car.equals("Tesla")){
            return new Tesla();
        }
        return null;
    }
}

调用实现

package model.factory.simple;

public class Consumer {
    public static void main(String[] args) {
        // 1. 了解这个接口和实现类才能new出来
//        Car car1=new WuLing();
//        Car car2=new Tesla();
//        car1.name();
//        car2.name();

        //2. 使用工厂创建
        Car car = CarFactory.getCar("五菱");
        Car tesla = CarFactory.getCar("Tesla");
        car.name();
        tesla.name();

    }
}

简单工厂模式简单易懂,但是如果要增加产品,就要修改源代码,破坏开闭规则。

工厂方法模式

在简单工厂模式的前提下,我们增加以下类
工厂方法模式类

package model.factory.method;

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

实现工厂方法

package model.factory.method;

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

package model.factory.method;

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

测试

package model.factory.method;


    public class Consumer {
        public static void main(String[] args) {
            Car car = new WuLingFactory().getCar();
            Car car1 = new TeslaFactory().getCar();

            car.name();
            car1.name();

        }
}

此时如果想再新增一个产品,只需实现工厂方法

package model.factory.method;

public class Mobai implements Car{
    @Override
    public void name() {
        System.out.println("摩拜单车");
    }
}

package model.factory.method;

public class MobaiFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new Mobai();
    }
}

由此发现,这样可以不破坏最初代码,但是繁琐了很多。

image.png

image.png

抽象工厂模式

抽象工厂模式简单来说就是工厂的工厂,具体的话,我们先看个例子

首先我们先写一个手机的接口

package model.factory.abstract1;

//手机产品接口
public interface PhoneProduct {
    void start();
    void shutdown();
    void callup();
    void sendSMS();
}

我们在来写一个路由器的接口

package model.factory.abstract1;

//路由器产品接口
public interface RouterProduct {
    void start();
    void shutdown();
    void openWifi();
    void setting();
}

现在有华为和小米两个产品

package model.factory.abstract1;

public class HuaWeiPhone implements PhoneProduct{
    @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("华为发短信");
    }
}

package model.factory.abstract1;

public class HuaWeiRouter implements RouterProduct{
    @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("华为路由器设置");
    }
}

package model.factory.abstract1;

public class XiaomiPhone implements PhoneProduct{
    @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("小米发短信");
    }
}

package model.factory.abstract1;

//小米路由器
public class XiaomiRouter implements RouterProduct{
    @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("小米路由器设置");
    }
}

这样我们有了两个接口和对应各自的实现类
但是这样还没有体现本节内容

所以我们加入抽象工厂

package model.factory.abstract1;

//抽象产品工厂
public interface ProductFactory {
    //生产手机
    PhoneProduct phoneProduct();

    //生产路由器
    RouterProduct routerProduct();

}

有了抽象工厂,我们还不能指定到底是生产华为的手机还是小米的路由器,所以

package model.factory.abstract1;

public class HuaWeiFactory implements ProductFactory{
    @Override
    public PhoneProduct phoneProduct() {
        return new HuaWeiPhone();
    }

    @Override
    public RouterProduct routerProduct() {
        return new HuaWeiRouter();
    }
}

package model.factory.abstract1;

public class XIaomiFactory implements ProductFactory{
    @Override
    public PhoneProduct phoneProduct() {
        return new XiaomiPhone();
    }

    @Override
    public RouterProduct routerProduct() {
        return new XiaomiRouter();
    }
}

增加测试类:

package model.factory.abstract1;

public class Client{
    public static void main(String[] args) {
        System.out.println("===========小米");
        //小米工厂
        XIaomiFactory xIaomiFactory = new XIaomiFactory();
        PhoneProduct phoneProduct = xIaomiFactory.phoneProduct();
        phoneProduct.callup();
        phoneProduct.sendSMS();
        RouterProduct routerProduct = xIaomiFactory.routerProduct();
        routerProduct.openWifi();


        System.out.println("============华为");
        HuaWeiFactory huaWeiFactory = new HuaWeiFactory();
        PhoneProduct phoneProduct1 = huaWeiFactory.phoneProduct();
        phoneProduct1.callup();
        RouterProduct routerProduct1 = huaWeiFactory.routerProduct();
        routerProduct1.openWifi();
    }

}

最后的关系如下:
image.png

调理一遍:
用户选择工厂,工厂实现了抽象工厂的内容,然后用户根据需求调用所需要的产品。

建造者模式

由上面的工厂模式,我们可以理解为创建了一个族的产品,然建造者就是把这些东西组装起来变成一个类。
比如,造房子的过程。
我们先要有地基,然后钢筋工厂,然后铺电线,粉刷。最后形成一个房子。
建造者,模式,就是抽象成一个指挥者,你去控制工人们怎么做。蓝图在你这里,你只管决定然后做出最后的产品。
如下:

package model.builder.demo1;

//抽象的建造者 : 定义 方法
public abstract class Builder {
    abstract void buildA();//地基
    abstract void buildB();//钢筋工厂
    abstract void buildC();//电线
    abstract void buildD();//粉刷

    //得到产品
    abstract Product getProduct();

}

package model.builder.demo1;

//具体的建造者: 工人
public class Worker extends Builder{
    private Product product;

    public Worker() {
        this.product = new Product();
    }

    @Override
    void buildA() {
        product.setBulidA("地基");
        System.out.println("地基");
    }

    @Override
    void buildB() {
        product.setBulidB("钢筋工程");
        System.out.println("钢筋");
    }

    @Override
    void buildC() {
        product.setBulidC("电线");
        System.out.println("电线");
    }

    @Override
    void buildD() {
        product.setBulidD("粉刷");
        System.out.println("粉刷");
    }

    @Override
    Product getProduct() {
        return product;
    }
}

package model.builder.demo1;

//产品 : 房子
public class Product {
    private String bulidA;
    private String bulidB;
    private String bulidC;
    private String bulidD;
    public String getBulidA() {
        return bulidA;
    }

    public void setBulidA(String bulidA) {
        this.bulidA = bulidA;
    }

    public String getBulidB() {
        return bulidB;
    }

    public void setBulidB(String bulidB) {
        this.bulidB = bulidB;
    }

    public String getBulidC() {
        return bulidC;
    }

    public void setBulidC(String bulidC) {
        this.bulidC = bulidC;
    }

    public String getBulidD() {
        return bulidD;
    }

    public void setBulidD(String bulidD) {
        this.bulidD = bulidD;
    }

    @Override
    public String toString() {
        return "Product{" +
                "bulidA='" + bulidA + '\'' +
                ", bulidB='" + bulidB + '\'' +
                ", bulidC='" + bulidC + '\'' +
                ", bulidD='" + bulidD + '\'' +
                '}';
    }
}

package model.builder.demo1;

//指挥:核心  如何构建由他决定
public class Director {
    //指挥工人按照顺序造房子
    public Product build(Builder builder){
        builder.buildA();
        builder.buildB();
        builder.buildC();
        builder.buildD();
        return builder.getProduct();
    }
}

package model.builder.demo1;

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

但是这样,只是定死的内容,我们大多数场景,是由用户为指挥者。
我们举例为麦当劳,里面有套餐还可以用户自定义 就是单点。

初始值就为套餐

package model.builder.demo2;

//建造者
public abstract class Bulider {

    public abstract Bulider buliderA(String msg);//汉堡
    public abstract Bulider buliderB(String msg);//可乐
    public abstract Bulider buliderC(String msg);//薯条
    public abstract Bulider buliderD(String msg);//甜点

    abstract Product getProduct();
}

package model.builder.demo2;

//产品、套餐
public class Product {

    private String BuildA="汉堡";
    private String BuildB="可乐";
    private String BuildC="薯条";
    private String BuildD="甜点";

    public void setBuildA(String buildA) {
        BuildA = buildA;
    }

    public void setBuildB(String buildB) {
        BuildB = buildB;
    }

    public void setBuildC(String buildC) {
        BuildC = buildC;
    }

    public void setBuildD(String buildD) {
        BuildD = buildD;
    }

    @Override
    public String toString() {
        return "Product{" +
                "BuildA='" + BuildA + '\'' +
                ", BuildB='" + BuildB + '\'' +
                ", BuildC='" + BuildC + '\'' +
                ", BuildD='" + BuildD + '\'' +
                '}';
    }
}

package model.builder.demo2;

//具体建造者
public class Worker extends Bulider{
    private Product product;

    public Worker() {
        this.product = new Product();
    }

    @Override
    public Bulider buliderA(String msg) {
        product.setBuildA(msg);
        return this;
    }

    @Override
    public Bulider buliderB(String msg) {
        product.setBuildB(msg);
        return this;
    }

    @Override
    public Bulider buliderC(String msg) {
        product.setBuildC(msg);
        return this;
    }

    @Override
    public Bulider buliderD(String msg) {
        product.setBuildD(msg);
        return this;
    }

    @Override
    Product getProduct() {
        return product;
    }
}

package model.builder.demo2;

public class Test {
    public static void main(String[] args) {
        //服务员
        Worker worker=new Worker();
        Product product = worker.buliderA("全家桶")
                .getProduct();
        System.out.println(product.toString());
    }
}

这样我们就可以自定义建造什么了。

原型模式

原型模式就是当我们new出来一个对象,如果想克隆这个对象,不用new 而是把这个对象当作一个原型所引用。
我们举个例子,视频搬运。

package model.prototype.demo1;

import java.util.Date;

/*
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(String name, Date createTime) {
        this.name = name;
        this.createTime = createTime;
    }

    public Video() {
    }

    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 +
                '}';
    }
}

package model.prototype.demo1;


import java.util.Date;

/*
客户端: 克隆
 */
public class Bilibili {
    public static void main(String[] args) throws CloneNotSupportedException {
        //原型对象
        Date date = new Date();
        Video v1 = new Video("三金", date);
        System.out.println(v1);
        System.out.println("hash="+v1.hashCode());


        //v1可以克隆v2
        Video v2 = (Video) v1.clone();//克隆出来的对象和原来一样
        System.out.println(v2);
        System.out.println("hash="+v2.hashCode());

        v2.setName("克隆三金");

        System.out.println(v2);

    }
}

结果是

Video{name='三金', createTime=Wed Apr 21 19:04:56 GMT+08:00 2021}
hash=1735600054
Video{name='三金', createTime=Wed Apr 21 19:04:56 GMT+08:00 2021}
hash=21685669
Video{name='克隆三金', createTime=Wed Apr 21 19:04:56 GMT+08:00 2021}

但是如果我们改变的了date的值,发现v1 v2都会改变。这就是浅克隆。
基本类型值会相互克隆,引用类型会指向相同的地址。
一般我们都希望互不干扰,就是深克隆。
所以我们重写clone方法。

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object clone =super.clone();
        Video v= (Video) clone;
        v.createTime= (Date) this.createTime.clone();
        return clone;
    }
Video{name='三金', createTime=Thu Jan 01 12:12:31 GMT+08:00 1970}
Video{name='克隆三金', createTime=Wed Apr 21 19:12:32 GMT+08:00 2021}

这样就可以变成一对一的了

适配器模式

适配器模式我们可以想象成电脑网线转换器
image.png

适配器就是让两个东西相互兼容,相互影响。
举例如下:
网线-适配器-usb

网线:

package model.adapter;

//要被适配的类 : 网线
public class Adaptee {
    public void request(){
        System.out.println("连接网线上网。");
    }
}

适配器:

package model.adapter;

//真正的适配器  需要连接usb 网线
public class Adapter extends Adaptee implements NetToUSB{
    @Override
    public void handleRequest() {
        super.request();//可以上网了
    }
}

usb:

package model.adapter;

//接口转换器的抽象实现
public interface NetToUSB {

    //处理请求  把网线插到usb
    public void handleRequest();
}

测试:

package model.adapter;

//客户端类 : 想上网,插不上网线
public class Computer {
    //我们电脑需要连接到转接器才能上网
    public void net(NetToUSB adapter){
        //上网的具体实现  找一个转接头
        adapter.handleRequest();
    }

    public static void main(String[] args) {
        //电脑 适配器 网线
        Computer computer = new Computer();//电脑
        Adapter adapter = new Adapter();//转接器
        Adaptee adaptee = new Adaptee();//网线


        computer.net(adapter);
    }
}

这样就简单的实现了适配器模式的基本用途。

但是我们不想只要这一根网线进这一个适配器(因为用了继承)
所以对适配器进行改进

package model.adapter;

//组合
//对象适配器
public class Adapter2 implements NetToUSB{

    private Adaptee adaptee;

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

    @Override
    public void handleRequest() {
        adaptee.request();
    }
}

这样每次调用的时候可以指定网线了。

package model.adapter;

//客户端类 : 想上网,插不上网线
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 adapter2 = new Adapter2(adaptee);//转接线2


        computer.net(adapter2);
    }
}

要体会这里的思想。

桥接模式

我们看下面的图
image.png
如果想获得苹果笔记本电脑 或者 联想台式电脑 该如何呢。
我们应该在这两个直接搭一个桥梁(可能有点像适配器模式,不过是不一样的,我们需要仔细考虑考虑)
image.png

我们根据上述建立代码

package model.bridge;

public interface Brand {

    void info();
}

package model.bridge;

//苹果品牌
public class Apple implements Brand{
    @Override
    public void info() {
        System.out.println("苹果");
    }
}

package model.bridge;

//联想品牌
public class Lenovo implements Brand{
    @Override
    public void info() {
        System.out.println("联想");
    }
}

一个分支结束。

package model.bridge;

//抽象的电脑类型类
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("笔记本");
    }
}

这里我们使用了组合 ,通过构造器让两个分支有了联系。

这里如果体会不到好处的话 ,我再画一个图
image.png
这样就会变成多继承的关系。

所以就体现出了桥接的好处。

代理模式

为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP 和 Spring MVC】面试必问

代理模式的分类:

  • 静态代理
  • 动态代理

静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
  • 客户:访问代理对象的人

代码步骤:

  1. 接口
package com.sanjin.demo01;

//租房
public interface Rent {
    public void rent();
}
  1. 真实角色
package com.sanjin.demo01;

//房东
public class Host implements Rent{
    public void rent() {
        System.out.println("房东要出租房子");
    }
}
  1. 代理角色
package com.sanjin.demo01;

public class Proxy implements Rent{

    private Host host;


    public Proxy(Host host) {
        this.host = host;
    }

    public Proxy() {
    }

    public void rent() {
        host.rent();
        seeHouse();
        fee();
        contract();
    }

    //看房
    public void seeHouse(){
        System.out.println("中介带你看房");
    }
    //收中介费
    public void fee(){
        System.out.println("收中介费");
    }
    //合同
    public void contract(){
        System.out.println("签租赁合同");
    }

}
  1. 客户端访问代理角色
package com.sanjin.demo01;

public class Client {
    public static void main(String[] args) {
        //房东要租房子
        Host host = new Host();
        //代理,中介帮房东租房子,代理角色一般会有附属操作
        Proxy proxy = new Proxy(host);
        //你不用面对房东,直接找中介
        proxy.rent();
    }
}

代理模式的好处:

  • 可以使真实角色的操作更加纯粹,不用去关注一些公共业务
  • 公共业务就交给代理角色,实现了业务的分工
  • 公共业务发生拓展的时候,方便集中管理!

缺点:

  • 一个真实角色,就会又一个代理角色,代码量会翻倍,开发效率会变低

加深理解

  1. 接口
package com.sanjin.demo02;

public interface UserService {
    void add();
    void delete();
    void apdate();
    void query();
}
  1. 真实角色
package com.sanjin.demo02;

//真实对象
public class UserServiceImpl implements UserService{
    public void add() {

        System.out.println("增加了一个用户");
    }

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

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

    public void query() {
        System.out.println("查找了一个用户");
    }
}
  1. 代理角色
package com.sanjin.demo02;

//代理增加日志
public class UserServiceProxy implements UserService{

    private UserServiceImpl userService;

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

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

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

    public void apdate() {
        log("upd");
        userService.apdate();
    }

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

    //日志方法
    public void log(String msg){
        System.out.println("使用了"+msg+"方法");
    }
}
  1. 客户端
package com.sanjin.demo02;

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

        UserServiceProxy userServiceProxy = new UserServiceProxy();
        userServiceProxy.setUserService(userService);
        userServiceProxy.add();
    }
}

动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理;基于类的动态代理
    • 基于接口— JDK 动态代理【我们再这里使用】
    • 基于类:cglib
    • java字节码实现:javassist

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

InvocationHandler

动态代理类

package com.sanjin.domo04;

import com.sanjin.demo03.Rent;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//我们会用这个类 自动生成代理类
public class Proxy2 implements InvocationHandler {
    //被代理的接口
    private Object target;

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

    public Object getProxy(){
      return   Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    //处理代理实例,并返回结果
    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 mes){
        System.out.println("执行了"+mes+"日志方法");
    }


}

测试类

package com.sanjin.domo04;

import com.sanjin.demo02.UserService;
import com.sanjin.demo02.UserServiceImpl;

public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService = new UserServiceImpl();

        //代理角色
        Proxy2 proxy2 = new Proxy2();
        proxy2.setTarget(userService);//设置要代理的对象
        //动态生成代理类
        UserService proxy = (UserService) proxy2.getProxy();
        proxy.add();
        proxy.delete();

    }
}

动态代理的好处:

  • 可以使真实角色的操作更加纯粹,不用去关注一些公共业务
  • 公共业务就交给代理角色,实现了业务的分工
  • 公共业务发生拓展的时候,方便集中管理!
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值