Java设计模式(代理模式-模板方法模式-命令模式)

本文深入解析了Java中的代理模式(静态代理、JDK动态代理与Cglib代理)、模板方法模式(经典与钩子方法)以及命令模式的原理、代码实现和应用场景。掌握这些模式有助于提升代码结构和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.代理模式

1.1 代理模式概述

(1)基本介绍

①为一个对象提供一个替身,以控制对这个对象的访问,即通过代理对象
	访问目标对象,这样做的好处:可以在目标对象实现的基础上,增强额
	外的功能操作,即扩展目标对象的功能

②被代理的对象可以是远程对象,创建开销大的对象或者需要安全控制的对象

③代理模式有不同的形式,主要有三种,静态代理,动态代理(JDK代理或者
	接口代理),Cglib代理(在内存中动态创建对象,而不需要实现接口)

(2)代理模式原理类图
在这里插入图片描述

1.2 静态代理

1.2.1 静态代理概述

(1)基本介绍

1)优点:在不修改目标对象功能的前提下,能通过代理对象对目标对像
	功能扩展

2)缺点:因为代理对象需要和目标对象实现一样的接口,所以会有很多
代理类

3)一旦接口增加方法,目标对象和代理对象都需要维护

(2)类图
在这里插入图片描述

1.2.2 代码理解

1.接口类

package com.pattern.设计模式.代理模式.静态代理;

public interface ITeacherDao {

    void teacher();
}

2.TeacherDao 对象类

package com.pattern.设计模式.代理模式.静态代理;

public class TeacherDao implements ITeacherDao{

    @Override
    public void teacher() {
        System.out.println("老师在上课>>>>>>>>");

    }
}

3.代理对像类

package com.pattern.设计模式.代理模式.静态代理;

public class TeacherDaoProxy implements ITeacherDao{

    private ITeacherDao iTeacherDao;  // 目标对象,通过接口聚合

    public TeacherDaoProxy(ITeacherDao iTeacherDao){
        this.iTeacherDao = iTeacherDao;

    }

    @Override
    public void teacher() {
        System.out.println("代理开始>>>>>");
        iTeacherDao.teacher();
        System.out.println("代理结束<<<<<");
    }
}

4.测试类

package com.pattern.设计模式.代理模式.静态代理;

public class Test {
    public static void main(String[] args) {
        // 创建被代理对象
        TeacherDao teacherDao = new TeacherDao();

        // 创建代理对象 同时将被代理对象传递给代理对像
        TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);

        // 通过代理对象,调用到被代理对象的方法
        teacherDaoProxy.teacher();

    }
}

1.3 动态代理之JDK代理

1.3.1 动态代理之JDK代理概述

(1)基本介绍

	1)代理对象不需要实现接口,但是目标对象要实现接口,否则不能用
		动态代理

	2)代理对象的生产是利用JDK和API,动态的在内存中构建代理对象

	3)动态代理也叫JDK代理,接口代理

(2)类图
在这里插入图片描述

1.3.2 代码理解

1.还是接口类

package com.pattern.设计模式.代理模式.动态代理;

public interface ITeacherDao {

    void teacher();
}

2.还是TeacherDao 对象类

package com.pattern.设计模式.代理模式.动态代理;

public class TeacherDao implements ITeacherDao {


    @Override
    public void teacher() {
        System.out.println("正在上课>>>>>>>>>>>");
    }
}

3.代理对象类

package com.pattern.设计模式.代理模式.动态代理;

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

public class ProxyFactory {

    // 维护一个目标对象 Object
    private Object object;

    public ProxyFactory(Object object){
        this.object = object;

    }

    // 给目标对象生成一个代理对象
    public Object getProxyInstance(){
        /**
         * 第一个参数:指定当前目标对象使用的类加载器,获取加载器的方法固定
         *
         * 第二个参数:目标对像实现的接口类型,使用泛型方法确认类型
         *
         * 第三个参数:事情处理,执行目标对象的方法时,会触发事情处理器方法,
         * 会把当前执行的目标对象方法作为参数传入
         */
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),
                object.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("JDK代理开始");
                        // 反射机制调用目标对象的方法
                        Object invoke = method.invoke(object, args);
                        return invoke;
                    }
        });
    }
}

4.测试类

package com.pattern.设计模式.代理模式.动态代理;

public class Test {
    public static void main(String[] args) {
        // 创建目标对象
        TeacherDao teacherDao = new TeacherDao();

        // 给目标对象创建代理对象 可以转成 ITeacherDao
        ITeacherDao proxyFactory = (ITeacherDao) new ProxyFactory(teacherDao).getProxyInstance();
        System.out.println(proxyFactory);

        proxyFactory.teacher();

    }
}

1.4 动态代理之Cglib代理

1.4.1 动态代理之Cglib代理概述

(1)基本介绍

	1)静态代理和JDK代理模式都要求目标对象实现一个接口,但是
		有时候目标对象只是一个单独的对象,并没有实现任何的接口,
		这个时候可以使用目标对象子类来实现代理,这就是Cglib代理

	2)Cglib代理也叫做子类代理,它是在内存中构建一个子类对象从
		而实现对目标对象功能扩展,Cglib也有人将其归属到动态代理

	3)Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展
		java类和实现java接口,它广泛的被许多AOP框架使用,比如 
		Spring AOP,实现方法拦截

	4).a.目标对象需要实现接口:用JDK模式 
	   b.目标对象不需要实现接口:用Cglib模式

	5)Cglib包底层通过使用字节码处理框架ASM来转换字节码并生成新的类

(2)类图
在这里插入图片描述

1.4.2 代码理解

1.这个不同的区别就在不需要接口了,直接对象类

package com.pattern.设计模式.代理模式.Cglib代理;

public class TeacherDao {

    public void teacher(){
        System.out.println("老师正在上课");
    }
}

2.代理对象类

package com.pattern.设计模式.代理模式.Cglib代理;

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

import java.lang.reflect.Method;

public class ProxyFactory implements MethodInterceptor {

    // 聚合一个目标对象
    private Object object;

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

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

    // 重写 intercept方法 会调用目标对象的方法
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib代理农事开始");
        Object invoke = method.invoke(object, objects);
        System.out.println("Cglib代理提交");
        return invoke;
    }
}

3.测试

package com.pattern.设计模式.代理模式.Cglib代理;

public class Test {
    public static void main(String[] args) {
        // 创建目标对象
        TeacherDao teacherDao = new TeacherDao();

        // 获取到代理对象 并且将目标对象传给代理对象
        TeacherDao proxyInstance = (TeacherDao) new ProxyFactory(teacherDao).getProxyInstance();

        proxyInstance.teacher();

    }
}

2.模板方法模式

2.1 模板方法模式概述

(1)基本介绍

①模板方法模式,又叫模板模式,在一个抽象类公开定义了执行它的
	方法的模板,它的子类可以按需要重写方法实现,但调用将以抽象类
	中定义的方式进行

②简单来说,模板方法定义一个操作中的树算法骨架,而将一些步骤延迟
	到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法
	的某些特定步骤

③这种类型的设计模式属于行为型模式

(2)原比类图
在这里插入图片描述
(3)代码类图
在这里插入图片描述

(3)模板方法模式在spring IOC容器初始化时运用到了。

(4)模板方法模式注意事项和细节

1.基本思想是算法只存在一个地方,也就是方法中,容易修改,需要修改
	算法时,只需要修改父类的模板方法或者已经实现的某些步骤,子类就
	会继承这些修改

2.实现了最大化代码复用。父类的模板方法和实现的某些步骤会被子类
	继承而直接使用

3.即统一了算法,又提供了很大的灵活性,父类的模板方法确保了算法
	的结构保持不变,同时由子类提供部分步骤的实现

4.该模式的不足之处:每一个不同实现都需要一个子类实现,导致类
	的个数增加,使得系统更加庞大

5.一般模板方法都加上final关键字,防止子类重写模板方法

6.使用场景:当要完成某个过程,该过程要执行一系列步骤,这一系列
	的步骤基本相同,但个别步骤在实现时可能不同,可以使用该模式

2.1.1 代码理解

1.模板方法类

package com.pattern.设计模式.模板方法模式.正常模板方法模式;

public abstract class SoyMilk {

    // 模板方法 模板方法可以做成final, 不让子类去继承
    final void make(){
        select();
        add();
        soak();
        beat();
    }

    void select(){
        System.out.println("选择材料-黄豆");

    }

    // 添加配料--但是配料不固定,可以是任何口味,所以定义成抽象方法
    abstract void add();

    void soak(){
        System.out.println("浸泡一段时间");

    }

    void beat(){
        System.out.println("将材料放到豆浆机");
    }
}

2.子类1

package com.pattern.设计模式.模板方法模式.正常模板方法模式;

public class RedSoy extends SoyMilk{
    @Override
    void add() {
        System.out.println("加入红豆配料");
    }
}

3.子类2

package com.pattern.设计模式.模板方法模式.正常模板方法模式;

public class GreenSoy extends SoyMilk {
    @Override
    void add() {
        System.out.println("加入绿豆配料");
    }
}

4.测试

package com.pattern.设计模式.模板方法模式.正常模板方法模式;

public class Test {
    public static void main(String[] args) {
        // RedSoy

        SoyMilk redSoy = new RedSoy();
        redSoy.make();

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>");
        // GreenSoy
        SoyMilk greenSoy = new GreenSoy();
        greenSoy.make();
    }
}

2.2 模板方法模式之钩子方法

(1)基本介绍

①本质跟前面的没什么关系,只是增加了一个方法,去判断中间某个
	方法要不要实现

2.2.1 代码理解

1.模板方法-加上钩子方法

package com.pattern.设计模式.模板方法模式.钩子方法模板模式;

public abstract class SoyMilk {

    // 模板方法 模板方法可以做成final, 不让子类去继承
    final void make(){
        select();
        if (getGouZi()){
            add();
        }
        soak();
        beat();
    }

    void select(){
        System.out.println("选择材料-黄豆");

    }

    // 添加配料--但是配料不固定,可以是任何口味,所以定义成抽象方法
    abstract void add();

    void soak(){
        System.out.println("浸泡一段时间");

    }

    void beat(){
        System.out.println("将材料放到豆浆机");
    }

    // 钩子方法
    boolean getGouZi(){
        return true;
    }

}

2.子类 加配料

package com.pattern.设计模式.模板方法模式.钩子方法模板模式;

public class RedSoy extends SoyMilk {
    @Override
    void add() {
        System.out.println("加入红豆配料");
    }
}

3.子类 不加配料

package com.pattern.设计模式.模板方法模式.钩子方法模板模式;

public class Soy extends SoyMilk{

    @Override
    void add() {
        // 因为不需要加配料,所以空实现

    }

// 注意这里
    @Override
    boolean getGouZi() {
        return false;
    }
}

4.测试

package com.pattern.设计模式.模板方法模式.钩子方法模板模式;

public class Test {
    public static void main(String[] args) {
        // RedSoy

        SoyMilk redSoy = new RedSoy();
        redSoy.make();

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>");
        // GreenSoy
        SoyMilk greenSoy = new GreenSoy();
        greenSoy.make();

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>");
        // Soy
        SoyMilk soy = new Soy();
        soy.make();
    }
}

3.命令模式

3.1 命令模式概述

(1)基本介绍

①在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的
	接收对象是谁,也不知道被请求的操作是谁,我们只需要在程序运行时指
	定具体的请求接受者即可。此时,可以使用命令模式来设计

②命令模式使得请求发送者和请求接受者消除彼此之间的耦合度,让对象之
	间的调用更加灵活,实现解耦

③在命令模式中,会将一个请求封装成一个对象,以便使用不同的参数来表
	示不同的请求,同时命令模式也支持取消的操作,

(2)原理类图
在这里插入图片描述
Invoker:调用者角色
Command:命令角色,需要执行的命令都在这里,可以是接口或者抽象类
Receiver:接受者角色,知道如何实施和执行一个请求象关的操作
ConcreteCommand:将一个接受者对象与一个动作,调用接收者相应的操作,实现execute
(3)代码类图
在这里插入图片描述
PS:JDBCTemplate中使用到了命令模式
在这里插入图片描述

3.2 代码理解

1.Command接口类

package com.pattern.设计模式.命令模式;

public interface Command {

    public void execute(); // 打开
    public void undo(); // 取消
}

2.LightOffCommand 类

package com.pattern.设计模式.命令模式;

public class LightOffCommand implements Command{

    LightReceiver lightReceiver;

    public LightOffCommand(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        lightReceiver.off();
    }

    @Override
    public void undo() {
        lightReceiver.on();
    }
}

3.LightOnCommand 类

package com.pattern.设计模式.命令模式;

public class LightOnCommand implements Command{

    LightReceiver lightReceiver;

    public LightOnCommand(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        lightReceiver.on();
    }

    @Override
    public void undo() {
        lightReceiver.off();
    }
}

4.NoCommand 类

package com.pattern.设计模式.命令模式;

public class NoCommand implements Command{
    @Override
    public void execute() {

    }

    @Override
    public void undo() {

    }
}

5.LightReceiver 类

package com.pattern.设计模式.命令模式;

public class LightReceiver {

    public void on(){
        System.out.println("电灯打开了");

    }

    public void off(){
        System.out.println("电灯关闭了");
    }
}

6.RemoteController 类

package com.pattern.设计模式.命令模式;

public class RemoteController {

    // 开 命令数组
    Command[] onCommands;
    Command[] offCommands;

    // 撤销的命令
    Command undoCommand;

    // 构造器 完成对按钮的初始化
    public RemoteController(){
        onCommands = new Command[5];
        offCommands = new Command[5];

        for (int i = 0; i < 5; i++){
            onCommands[i] = new NoCommand();
            offCommands[i] = new NoCommand();

        }
    }

    // 给按钮设置需要的命令
    public void setCommand(int no, Command onCommand, Command offCommand){
        onCommands[no] = onCommand;
        offCommands[no] = offCommand;

    }

    // 按下开的按钮
    public void onButton(int no){
        onCommands[no].execute();
        // 记录这次的操作,用于撤销
        undoCommand = onCommands[no];

    }

    // 按下关的按钮
    public void offButton(int no){
        offCommands[no].execute();
        // 记录这次的操作,用于撤销
        undoCommand = offCommands[no];

    }

    // 按下撤销按钮
    public void undoButton(){
        undoCommand.undo();
    }
}


7.测试类

package com.pattern.设计模式.命令模式;

public class Test {
    public static void main(String[] args) {

        // 使用命令模式,完成通过遥控器对电灯的操作
        // 创建电灯的对象
        LightReceiver lightReceiver = new LightReceiver();
        // 创建电灯打开的命令
        LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
        LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);

        // 创建遥控器
        RemoteController remoteController = new RemoteController();
        // 给遥控器设置相关的命令 no==0 是电灯的开关操作
        remoteController.setCommand(0, lightOnCommand, lightOffCommand);

        remoteController.onButton(0);
        remoteController.offButton(0);
        remoteController.undoButton();


    }
}

4.访问者模式

访问者模式 等等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值