定义
首先描述下定义,然后举例说明。
网上定义
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许向对象添加新的功能或职责,同时保持对象类的原始结构。这种模式提供了一种替代继承的机制来扩展功能,因为继承通常是在编译时固定的,而装饰器模式则允许在运行时动态地添加行为。
理解
这边分一下结构,组成主要分为
1,组件接口:Component,定义基本行为
2,具体组件:Concrete Component,实现组件接口,是装饰器可以添加行为的基本对象
3,装饰器:也实现Component接口,并且有对该接口的引用,通常指向另一个具体装饰器或者具体组件。装饰器可以在被调用时将请求转发给引用的对象,也可以在转发后添加自己的行为。
4,具体装饰器,具体装饰器继承装饰器,会在不改变组件接口的前提下,加入新的功能。(核心)
ai举例
这里用的是通义千问(阿里的gpt2.5)
发出请求:
java的装饰器模式写个demo
ai回复的
下面我将使用装饰器模式来创建一个简单的文本输出系统,其中基础的Message类用于生成基本的消息,而装饰器则用于添加额外的行为,比如在消息前后加上标签或者转换消息大小写。
首先,我们定义一个抽象的接口MessageComponent,所有的消息组件都将实现这个接口:
public interface MessageComponent { void print(); }
接下来,我们创建一个基础的Message类,它实现了MessageComponent接口:
public class Message implements MessageComponent { private String text; public Message(String text) { this.text = text; } @Override public void print() { System.out.println(text); } }
现在我们创建一个装饰器基类MessageDecorator,它同样实现MessageComponent接口,并且持有MessageComponent类型的实例,这样就可以对传入的对象进行装饰:
public abstract class MessageDecorator implements MessageComponent { protected MessageComponent messageComponent; public MessageDecorator(MessageComponent messageComponent) { this.messageComponent = messageComponent; } @Override public void print() { messageComponent.print(); } }
然后,我们可以创建具体的装饰器类,例如TaggedMessage和UpperCaseMessage:
public class TaggedMessage extends MessageDecorator { private String tag; public TaggedMessage(MessageComponent messageComponent, String tag) { super(messageComponent); this.tag = tag; } @Override public void print() { System.out.print("<" + tag + ">"); super.print(); System.out.println("</" + tag + ">"); } } public class UpperCaseMessage extends MessageDecorator { public UpperCaseMessage(MessageComponent messageComponent) { super(messageComponent); } @Override public void print() { String upperText = ((Message)messageComponent).text.toUpperCase(); System.out.println(upperText); } }
最后,我们在主函数中使用这些类:
public class Main { public static void main(String[] args) { Message originalMessage = new Message("Hello, world!"); Message taggedMessage = new TaggedMessage(originalMessage, "h1"); Message upperCaseMessage = new UpperCaseMessage(taggedMessage); upperCaseMessage.print(); } }
运行这段代码,你会看到输出如下:
< h1 >HELLO, WORLD!</ h1 >
这就是一个使用装饰器模式的简单示例。装饰器模式的优点在于它可以灵活地增加功能而不改变现有代码,使得系统更加模块化和可扩展。
解析
可以看到提供了一个比较详细的例子,我们按结果顺一遍:
组件接口------>MessageComponent,ai定义了一个打印方法
具体组件------>Message类,实现上面的组件接口,并加入新的内容text,重写打印方法,使其打印出text的值。
装饰器------>抽象类MessageDecorator,也实现了上面的组件接口,加入新属性,重写的打印方法调用print()方法进行输出。
具体装饰器------>
TaggedMessage,ai为信息做了个分类,继承了装饰器,写了一个构造方法,用来创建对象,重写的print,做了自定义输出。
UpperCaseMessage,同上
最后写了一个测试方法
Message taggedMessage = new TaggedMessage(originalMessage, "h1");
上面就是基本创建对象,下面就开始爆红了
Message taggedMessage = new TaggedMessage(originalMessage, "h1"); Message upperCaseMessage = new UpperCaseMessage(taggedMessage);
错误为:incompatible type(数据类型不相容)
我将这个反馈给ai,然后ai就开始经典的所答非所问了,很多模型都有这个问题,有时候很聪明,你不问的他也帮完善,有时候就跟现在一样,陷入自己的思维误区里,继续追问只会让代码变复杂,几乎没可能得到解决办法。
但是代码归代码,我们还是可以参考一部分解释文本:
在UpperCaseMessage装饰器中直接将messageComponent转换成Message类型来获取text字段,这是不正确的,因为messageComponent可能是一个装饰器而不是原始的Message对象,它并不保证有text字段。
那根据ai的意思,类型转换错误,其实吧所有message换成messageComponent就行了,像这样
MessageComponent taggedMessage = new TaggedMessage(originalMessage, "h1"); MessageComponent taggedMessage = new TaggedMessage(originalMessage, "h1"); MessageComponent upperCaseMessage = new UpperCaseMessage(taggedMessage);
原因
在java里,你不能吧一个接口的实现直接赋值给另一个实现该类的变量,除非那个类本身也是该类的子类或者就是其本身,改动是因为MessageComponent类型是所有类(Message和所有装饰器)共有的超类型,这样,就可以将任何实现MessageComponent接口的类的对象赋值给这些变量。
关于ai
以上使我们自主修改的,但实际上我们既然已经依赖ai来给我们生成答案了,也应该尝试让ai这次会话走出这个误区,来实现我们的功能,不然总会出现代码多半只能用作参考,需要人为修改的情况。
首先,直接说解决问题的办法
新建一次会话,将你的全部代码发给ai,然后运行代码,将编译器报错的原因赋值给ai,这样它就会给你较为精准的回复,同时没有上一次会话的固定思维,这次会简介快速很多。
原因
有一些错误的问法会导致ai的行为和你预计的出现偏差,比如上面的报错,我如果直接询问:
Message taggedMessage = new TaggedMessage(originalMessage, "h1"); Message upperCaseMessage = new UpperCaseMessage(taggedMessage); 这两句代码发生报错incompatible type(数据类型不相容)
ai给出的回答格式就是:
在Java中,当你遇到“incompatible types”错误时,这通常意味着你正试图将一种类型的对象赋值给另一种不兼容的类型变量。在这个上下文中…
你的想表达的想法是:我提出来了有错的地方,你根据上下文帮我修改代码。
ai理解的是,你提出来了一个问题,再根据这个分析你的代码,帮你去完善代码。
这就出现了意见分歧,他会给你补充更多的代码,导致并未解决问题,反而代码越来越长,越来越乱。
这个时候,其实ai就已经陷入思维误区了,当本次对话你让他再去修改的时候,只要并未明说编译器的报错报文,它就会一直帮你完善下去,直到你放弃使用本次会话去完善。)
大概就是这个样子,对很多版本的ai代码完善功能也同样适用,当新建且直接提供编译器报错报文,比如这个:
的时候,ai的修复成功率最高。