享元和代理模式

文章目录

享元模式

1.引出享元模式

1.展示网站项目需求
2.传统方案解决
3.问题分析

2.享元模式

1.基本介绍
2.原理类图
3.外部状态和内部状态
4.类图
5.代码实现
1.AbsWebSite.java 抽象的网站
java 复制代码
package com.sun;

/**
 * Description: 抽象的网站
 * @Author sun
 * @Create 2024/6/6 19:45
 * @Version 1.0
 */
public abstract class AbsWebSite {
    public abstract void use(User user);
}
2.ConcreteWebSite.java 具体的网站,type属性是内部状态
java 复制代码
package com.sun;

/**
 * Description: 具体的网站
 * @Author sun
 * @Create 2024/6/6 19:46
 * @Version 1.0
 */
public class ConcreteWebSite extends AbsWebSite {

    // 网站的发布类型
    private String type = "";

    // 在创建网站时把具体的类型传进来
    public ConcreteWebSite(String type) {
        this.type = type;
    }

    @Override
    public void use(User user) {
        System.out.println("网站的发布类型为:" + type + user.getName() + "在使用中");
    }
}
3.WebSiteFactory.java 网站工厂,根据类型,获取对应类型的网站
java 复制代码
package com.sun;

import java.util.HashMap;

/**
 * Description: 网站的工厂类,根据需求,返回一个具体的网站
 * @Author sun
 * @Create 2024/6/6 19:49
 * @Version 1.0
 */
public class WebSiteFactory {

    // 一个集合,充当池的作用
    private HashMap<String, ConcreteWebSite> pool = new HashMap<>();

    public AbsWebSite getWebsiteCategory(String type) {
        // 如果池中没有包含对应类型的对象,就创建一个对象,放到池中
        if (!pool.containsKey(type)) {
            pool.put(type, new ConcreteWebSite(type));
        }
        // 只要到这里了就必然可以拿到对象
        return (AbsWebSite) pool.get(type);
    }

    // 获取池中的网站总数
    public int getWebSiteCount() {
        return pool.size();
    }
}
4.User.java 使用网站的用户,是外部状态
java 复制代码
package com.sun;

/**
 * Description: 享元模式中的外部状态
 * @Author sun
 * @Create 2024/6/6 20:12
 * @Version 1.0
 */
public class User {
    private String name;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
5.Client.java
java 复制代码
package com.sun;

/**
 * Description:
 * @Author sun
 * @Create 2024/6/6 20:02
 * @Version 1.0
 */
public class Client {
    public static void main(String[] args) {
        // 创建一个工厂类
        WebSiteFactory webSiteFactory = new WebSiteFactory();
        // 要一个以新闻形式发布的网站
        AbsWebSite webSite = webSiteFactory.getWebsiteCategory("新闻");
        webSite.use(new User("tom"));
        // 要一个以博客形式发布的网站,后面即使要更多相同类型的网站,都会直接从池中获取,而不会创建新的实例
        AbsWebSite webSite2 = webSiteFactory.getWebsiteCategory("博客");
        webSite2.use(new User("jack"));
        AbsWebSite webSite3 = webSiteFactory.getWebsiteCategory("博客");
        webSite3.use(new User("lisa"));
        AbsWebSite webSite4 = webSiteFactory.getWebsiteCategory("博客");
        webSite4.use(new User("milan"));
        int webSiteCount = webSiteFactory.getWebSiteCount();
        System.out.println("webSiteCount = " + webSiteCount);
    }
}
6.结果
6.小结

3.享元模式在Integer的应用

代理模式

1.基本介绍

1.介绍
2.简单类图

2.静态代理

1.基本介绍
2.类图
3.代码实现
1.目录结构
2.ITeacherDao.java 被代理的接口
java 复制代码
package com.sun.staticproxy;

/**
 * Description: 接口
 * @Author sun
 * @Create 2024/6/7 19:05
 * @Version 1.0
 */
public interface ITeacherDao {
    void teach();
}
3.TeacherDao.java 被代理的实现类
java 复制代码
package com.sun.staticproxy;

/**TeacherDaoProxy.java
 * Description: 实现类
 * @Author sun
 * @Create 2024/6/7 19:06
 * @Version 1.0
 */
public class TeacherDao implements ITeacherDao{
    @Override
    public void teach() {
        System.out.println("老师正在授课中");
    }
}
4.TeacherDaoProxy.java 静态代理类
java 复制代码
package com.sun.staticproxy;

/**
 * Description: 代理TeacherDao
 * @Author sun
 * @Create 2024/6/7 19:06
 * @Version 1.0
 */
public class TeacherDaoProxy implements ITeacherDao{

    // 使用构造器进行聚合
    private ITeacherDao teacherDao;

    public TeacherDaoProxy(ITeacherDao teacherDao) {
        this.teacherDao = teacherDao;
    }

    @Override
    public void teach() {
        System.out.println("代理开始");
        teacherDao.teach();
        System.out.println("代理结束");
    }
}
5.Client.java
java 复制代码
package com.sun.staticproxy;

/**
 * Description:
 * @Author sun
 * @Create 2024/6/7 19:11
 * @Version 1.0
 */
public class Client {
    public static void main(String[] args) {
        TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(new TeacherDao());
        teacherDaoProxy.teach();
    }
}
6.结果

2.动态代理(JDK代理)

1.基本介绍
2.类图
3.代码实现
1.ITeacherDao.java 被代理的接口
java 复制代码
package com.sun.dynamic;

/**
 * Description: 被代理的接口
 * @Author sun
 * @Create 2024/6/7 19:25
 * @Version 1.0
 */
public interface ITeacherDao {

    void teach(String name);

}
2.TeacherDao.java 被代理的类
java 复制代码
package com.sun.dynamic;

/**
 * Description: 实现类
 * @Author sun
 * @Create 2024/6/7 19:06
 * @Version 1.0
 */
public class TeacherDao implements ITeacherDao {

    @Override
    public void teach(String name) {
        System.out.println(name + "老师正在授课中");
    }

}
3.ProxyFactory.java 代理工厂,返回动态代理对象
java 复制代码
package com.sun.dynamic;

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

/**
 * Description: 动态代理对象,可以对其代理的对象的任意方法添加任意操作
 * @Author sun
 * @Create 2024/6/7 19:27
 * @Version 1.0
 */
public class ProxyFactory {

    // 构造器聚合一个目标对象
    private Object target;

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

    // 给目标对象,生成一个代理对象
    public Object getProxyInstance() {
        /**
         * 参数说明:
         * ClassLoader loader:指定当前目标对象使用的类加载器
         * Class<?>[] interfaces:是目标对象实现的接口类型,使用泛型方法确认类型
         * InvocationHandler h:是事件处理,当使用代理对象调用目标对象的方法时会触发
         */
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            /**
             * method:目标方法的Method对象,可以用来调用目标任何方法
             * args:目标方法的参数,也就是动态代理对象调用目标任何方法时传入的参数
             * @return 返回调用目标方法的返回值,也可以返回null
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("method = " + method + ", args = " + Arrays.toString(args));
                System.out.println("动态代理开始");
                /*
                invoke方法的第一个参数是目标对象,第二个参数的目标方法的参数
                 */
                Object result = method.invoke(target, args);
                System.out.println("动态代理结束");
                return result;
            }
        });
    }
}
4.Client.java
java 复制代码
package com.sun.dynamic;

/**
 * Description:
 * @Author sun
 * @Create 2024/6/7 19:47
 * @Version 1.0
 */
public class Client {
    public static void main(String[] args) {
        // 创建一个目标对象
        ITeacherDao target = new TeacherDao();
        // 得到代理对象
        ITeacherDao proxy = (ITeacherDao) new ProxyFactory(target).getProxyInstance();
        // 使用代理对象调用方法
        proxy.teach("李华");
    }
}
5.结果

3.Cglib代理

1.基本介绍
2.注意事项
3.类图
4.引入四个jar包
5.代码实现
1.目录结构
2.TeacherDao.java 被代理的类
java 复制代码
package com.sun.cglib;

/**
 * Description: 被代理的类
 * @Author sun
 * @Create 2024/6/8 19:37
 * @Version 1.0
 */
public class TeacherDao {

    public void teach(String name) {
        System.out.println(name + "老师授课中,使用的是cglib代理,不需要实现接口");
    }
}
3.ProxyFactory.java 返回代理对象的工厂
java 复制代码
package com.sun.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * Description:
 * @Author sun
 * @Create 2024/6/8 19:38
 * @Version 1.0
 */
public class ProxyFactory implements MethodInterceptor {

    // 构造器聚合一个目标对象
    private Object target;

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

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

    /**
     * 当使用代理对象调用目标对象的函数时,就会跳到这个函数,跟之前动态代理时类似
     * @param o
     * @param method 代理对象调用的目标对象的函数
     * @param args 函数的参数
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib代理模式开始");
        // 调用目标对象的函数
        System.out.println("method = " + method);
        System.out.println("args = " + args);
        Object returnVal = method.invoke(target, args);
        System.out.println("cglib代理结束");

        return returnVal;
    }
}
4.Client.java
java 复制代码
package com.sun.cglib;

/**
 * Description:
 * @Author sun
 * @Create 2024/6/8 19:50
 * @Version 1.0
 */
public class Client {
    public static void main(String[] args) {
        // 创建一个目标对象
        TeacherDao teacherDao = new TeacherDao();
        // 得到目标对象的代理对象
        ProxyFactory proxyFactory = new ProxyFactory(teacherDao);
        TeacherDao proxyInstance = (TeacherDao) proxyFactory.getProxyInstance();
        // 使用代理对象来调用目标对象函数,则会被代理
        proxyInstance.teach("小明");
    }
}
5.结果
6.几种变体
相关推荐
爱上电路设计3 小时前
有趣的算法
开发语言·c++·算法
studyForMokey3 小时前
kotlin 函数类型接口lambda写法
android·开发语言·kotlin
2401_858120264 小时前
探索sklearn文本向量化:从词袋到深度学习的转变
开发语言·python·机器学习
与墨学长5 小时前
Rust破界:前端革新与Vite重构的深度透视(中)
开发语言·前端·rust·前端框架·wasm
虫小宝5 小时前
Java中的软件架构重构与升级策略
java·开发语言·重构
CTGU_daffodil6 小时前
matlab 绘制高等数学中的二维函数示例
开发语言·matlab
立秋67896 小时前
使用Python绘制堆积柱形图
开发语言·python
逸群不凡6 小时前
C++|哈希应用->布隆过滤器
开发语言·数据结构·c++·算法·哈希算法
敲代码的小白帆6 小时前
跟着峰哥学java 第四天 商品分类 前后端显示
java·开发语言
friklogff6 小时前
【JavaScript脚本宇宙】美化网格布局:Isotope和Masonry让你的网页焕然一新
开发语言·前端·javascript