我有这段装饰模式的代码:
public interface AbstractComponent {
public void operation();
}
public class Component implements AbstractComponent {
public void operation() {
// do something
}
}
public abstract class AbstractDecorator implements AbstractComponent {
private AbstractComponent component;
public AbstractDecorator(AbstractComponent ac) {
component=ac;
}
public void operation() {
component.operation();
}
}
public class DecoratorA extends AbstractDecorator {
public DecoratorA (AbstractComponent ac) {
super(ac);
}
public void addedOperation() {
// adds features to Component
}
public void operation() {
addedOperation();
super.operation();
}
}
public class DecoratorB extends AbstractDecorator {
public DecoratorB (AbstractComponent ac) {
super(ac);
}
public void addedOperation() {
// adds features to Component
}
public void operation() {
addedOperation();
super.operation();
}
}
public class Tester {
public static void main(String args[]) {
AbstractComponent c = new Component();
AbstractComponent d1 = new DecoratorA(c);
AbstractComponent d2 = new DecoratorB(d1);
d2.operation();
}
}
创建DecoratorA
时,其构造函数调用超类构造函数,将引用c
分配给component
。创建DecoratorB
时,其构造函数调用相同的超类构造函数,将引用d1
分配给component
。
我的问题是:DecoratorB
构造函数不应覆盖c
到component
的过去作业吗?或者是否为我创建的每个装饰器提供了某种私有引用的副本?我找不到解决方案,因为这个引用是私有的,不能被子类继承。
答案 0 :(得分:1)
我的问题是:不应该
DecoratorB
构造函数覆盖c
到Component
的过去作业吗?'
没有。让我们看一个具有完全相同行为的稍微简单的情况:
class Parent {
int i;
}
class ChildA extends Parent {}
class ChildB extends Parent {}
public class Main {
public static void main(String[] args) {
Parent p1 = new ChildA();
Parent p2 = new ChildB();
p1.i = 3;
p2.i = 4;
System.out.println(p1.i); // Output: 3
}
}
正如您所看到的,Parent
的{{1}}的第二个分配不会更改第一个(无论您在构造函数中设置i
的位置 - 还是其他任何位置)。这是因为:
i
是实例变量。每个实例都为自己的i
分配了内存。这意味着引用int i
和p1
包含2 不同的 p2
- 更改一个不会改变另一个。
但是,如果您要声明int i
,那么static int i
将成为类变量,该变量将在该类的所有实例中共享。在这种情况下,第一个赋值将被第二个赋值覆盖。
如果您对手续感兴趣,JLS中有很多内容......
编辑:处理评论
在我的例子中,当我创建一个装饰器对象时,它的超类无法实例化,因为它是抽象的。所以我无法理解为什么每个装饰者都有自己的组件。
此处我们处于JLS技术细节中。
您说我们无法使用i
实例化abstract
课程。 JLS 8.1.1.1。 new MyAbstClass()
课程:
如果尝试使用类实例创建表达式(第15.9.1节)创建
abstract
类的实例,那么这是一个编译时错误。
可是:
可以实例化
abstract
类本身不是abstract
的子类,从而导致执行abstract
类的构造函数,从而执行字段该类的实例变量的初始值设定项。
当您实例化abstract
和DecoratorA
时,会调用DecoratorB
的构造函数并初始化实例字段AbstractComponent
。实际上,您确实有2个component
字段。
答案 1 :(得分:0)
它们是不同的对象,因此它不应该将组件赋值覆盖到c。
你有: 对象b,其组成部分是d1,和 对象d1,其组件为c