gpt4 book ai didi

java - 我对装饰模式的理解正确吗?

转载 作者:行者123 更新时间:2023-12-02 10:58:55 26 4
gpt4 key购买 nike

我目前正在学习装饰器模式。我编写这个程序是为了测试我的知识。我说得对吗?

public interface Logger {
void log(String msg);
}

public class BasicLogger implements Logger {

@Override
public void log(String msg) {
System.out.println("BasicLogger: " + msg);
}
}

这是我开始感到困惑的地方,如果我要在 HTMLLogger 类中重写它,那么装饰器中的 logger.log(msg) 有什么意义?

public class LoggerDecorator implements Logger {
Logger logger;
public LoggerDecorator(Logger logger) {
this.logger = logger;
}

@Override
public void log(String msg) {
logger.log(msg);
}
}

我是否应该复制 logger.log(msg); 行(或装饰器拥有的任何内容)?

public class HTMLLogger extends LoggerDecorator {
public HTMLLogger(Logger logger) {
super(logger);
}

@Override
public void log(String msg) {
logger.log(msg);
System.out.println("<HTML> HTML Logger" + msg);
//Generate the html file
}
}

最后,在演示类(class)中我有这个:

public LoggerTest() {
BasicLogger logger = new BasicLogger();
Logger htmlLogger = new HTMLLogger(new BasicLogger());
logger.log("Basic Logger log");
htmlLogger.log("HTML Logging");
}

输出为:

BasicLogger: Basic Logger log
BasicLogger: HTML Logging
<HTML> HTML LoggerHTML Logging

我确实需要对装饰器模式有深入的了解,因为我需要使用 AspectJ 来实现它。

最佳答案

您可能会缺少一条注释,其中包含诸如 /* your code here */ 之类的内容,作为子类化时应执行的操作的说明。

public class LoggerDecorator implements Logger {
Logger logger;
public LoggerDecorator(Logger logger) {
this.logger = logger;
}

@Override
public void log(String msg) {

/** YOUR CODE HERE WHEN SUBCLASSING **/

/**
* delegate to the base logger passed into the constructor to
* perform existing logging operations.
*/
logger.log(msg);
}
}

每次调用装饰器构造函数时,都会传入一个现有的记录器。该记录器被分配给一个私有(private)变量,并在重写的日志方法中使用。对于每个装饰,您可以向 logger.log 调用添加更多功能。

例如,当您实例化 HTMLLogger 时,您将添加一条 system.out 消息。作为练习,创建另一个名为 XMLLogger 的具体记录器,如下所示:

public class XMLLogger extends LoggerDecorator {
public XMLLogger(Logger logger) {
super(logger);
}

@Override
public void log(String msg) {
logger.log(msg);
System.out.println("<?xml version="1.0"?><message>XML Logger" + msg);
//Generate the xml file
}
}

然后将其添加到您的测试运行程序中:

public LoggerTest() {
BasicLogger logger = new BasicLogger();
Logger htmlLogger = new HTMLLogger(new BasicLogger());
Logger xmlAndHtmlLogger = new XMLLogger(new HTMLLogger());
logger.log("Basic Logger log");
htmlLogger.log("HTML Logging");
xmlAndHtmlLogger.log("I am Both HTML and XML logging");
}

输出:

BasicLogger: Basic Logger log
BasicLogger: HTML Logging
<HTML> HTML LoggerHTML Logging

BasicLogger: I am Both HTML and XML logging
<HTML> HTML LoggerI am Both HTML and XML logging
<?xml version="1.0"?><message>XML LoggerI am Both HTML and XML logging

在上面的输出中,我插入了一个空格,只是为了向您显示 xmlAndHtmlLogger.log 方法调用产生的输出。

装饰器模式的工作原理是扩展基类,向重写的方法添加额外的代码,然后委托(delegate)回原始方法。因此,对于您实例化的每个新装饰器子类,您都可以向该重写的方法添加更多功能。

由于 xmlAndHtmlLogger 是用 HTMLLogger 修饰的(它是从基类派生的),因此我们在调用该方法时可以获得所有三个的所有功能。您可以按任意顺序混合和匹配这些装饰器调用,以确定功能的顺序,甚至通过省略其中一个装饰器来省略某些功能。

<小时/>

装饰器模式的优点

我想澄清一下,装饰器模式的优点是,您可以创建具有不同混合匹配功能的不同对象组合,而不必为每个组合创建 N 个具体子类。在此示例中,使用 BaseLogger、HTMLLogger 和 XMLLogger,我们可以创建以下对象:

  • 一个基本记录器,不做任何花哨的事情。
  • HTML 记录器
  • XML 记录器
  • 还可以处理 XML 的 HTML 记录器!

第四个项目值得注意,因为它是两个装饰品的组合。假设我们还添加了以下附加装饰器:

  • JSONLogger
  • YAMLLogger

有了这两个额外的装饰器,我们现在可以在运行时创建以下对象:

  • 基本记录器,没什么花哨的。
  • HTMLLogger
  • XMLLogger
  • HTML 和 XML 记录器合二为一
  • HTML 和 JSON 记录器合二为一
  • HTML 和 YAML 记录器合二为一
  • HTML、XML 和 JSON 记录器合二为一
  • HTML、XML、JSON 和 YAML 合二为一
  • 等等

简而言之,我们不是为每个所需的组合创建具体的子类,而是简单地创建具有基本功能的简单类,然后通过将创建的对象链接到下一个对象的构造函数中,在运行时添加额外的功能。

因此,4 个装饰器可以产生超过 16 种不同的记录器组合!这是一个强大的概念,可以节省大量编码时间。

有关更深入的示例,请参阅 Wikipedia's WindowScrolling Example ,以及咖啡示例。记下测试运行器中的构造函数,您可以在其中清楚地看到每个对象传递回下一个类的构造函数。这就是“装饰”对象的过程。

关于java - 我对装饰模式的理解正确吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25474912/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com