【问题标题】:Create a subobject from the superobject从超对象创建子对象
【发布时间】:2013-06-17 20:41:36
【问题描述】:

我有 Class1 类的 object1。我想将 Class1 类扩展到 Class2 添加一个方法,然后创建 Class2 的 object2,它在所有方法中的行为都与 object1 完全相同,只是现在它会有一个附加方法。

Class1 object1 = new Class1();
Class2 object2 = new Class2(object1);
object2.oldMethod();
object2.newMethod();

object1.oldMethod 应该具有与 object2.oldMethod 完全相同的行为。一种愚蠢的方法是编写一个脚本,该脚本将生成具有所有 100 多个从 Class1 继承的方法的新类:

public class Class2 {
    private final Class1 object1;
    public Class2(Class1 object1) {
         this.object1 = object1;
    }

    public void oldMethod() {
        object1.oldMethod();
    }
    ...
    public void newMethod() {
    ...
    }
}

但我想比这更聪明。怎么样?

编辑: 我很抱歉没有让它更明确。我从某个第 3 方获得了 object1,这个对象带有一些内部状态 - 比如说之前在它上面运行了一些 setter。我需要让 object2 具有相同的内部状态(这是我在执行方法时的相同行为的意思)。我不能只扩展 Class1,然后从 Class2 中获取 object2。 object2 如何知道 object1 的状态?我不知道object1的内部状态(变量、数组、字段)。

EDIT2: 我想包装 object1,但不想为了保持不变而编写 100 个包装方法。

【问题讨论】:

  • 是什么阻止您在 Class1 中包含 newMethod
  • 是的...对我来说听起来像是继承! extends 关键字救援
  • 我没有修改 Class1 的权限,并且他们的 API 为我提供了 object1。
  • 你不必修改class1,你只需要让它可见。
  • Class1 是否实现了接口?如果是这样,您就有能力为拥有object1 的那个接口创建一个动态代理,除非您特别更改,否则将该接口中的任何方法发送到object1。你可以让代理拦截一两个方法来做不同的事情,你可以让代理使用object1 来执行新的方法。你不需要Class1的源代码,但你需要那个接口。但是如果你需要修改很多Class1的行为,或许你应该试试AspectJ。

标签: java design-patterns inheritance


【解决方案1】:

除非Object1 具有复制构造函数,否则您不能使用继承,因为您从API 接收Object1 的实例而不是自己构造它。

您可能想要的是Decorator Pattern。在这种模式中,装饰器由另一个对象组成,并通过装饰器向该对象添加功能。

class Object1 {
    //...stuff...
}

class Decorator {
    private Object1 object;
    public Decorator(Object1 obj) {
        object = obj;
    }
    public Object1 getComposite() {
        return object;
    }
    public void extra() {
        //Do stuff with object1 and any other state specific to the decorator
    }
}

这也可以作为继承来完成,但只有在您真正尝试扩展 Object1 的接口而不是简单地增强接口时才有意义。

作为单独的说明,我认为实际上尝试扩展第三方类是不明智的,除非文档清楚地表明该类是为扩展而设计的。将来的版本可能会将类标记为final,或者构造该类可能很复杂或具有包/私有访问权限。此外,根据您的编辑,它甚至可能是不可能的。 Object1 需要一个复制构造函数,以便您可以扩展它并从Object1 构造Object2 的实例。

【讨论】:

  • 是的,我要扩展object1的接口。
  • 如何调用 decorator.oldMethod()?
  • 你必须做类似decorator.getComposite().oldMethod()的事情。
  • 你说得对,就我而言,第三方 Class1 可以随时更改,这会破坏我的代码。
  • 我想另一个注意事项是,如果Object1 实现了一个接口IFoo,那么您可以让装饰器实现IFoo 并使用Eclipse IDE 生成委托方法。
【解决方案2】:
public class Class2 extends Class1{
    //signature of old method, with the same parameters (if exists).
    public void oldMethod(){
        super.oldMethod(); //call the Class1 method
        //do what you have to do for this class down here.
    }
}

这种行为称为多态性,在这种情况下,您将通用的东西委托给超类,并且只实现对您正在工作的类真正重要的东西。

【讨论】:

  • 不需要显式声明oldMethod,凭借继承(动态调度和虚拟方法)Class2 将只使用Class1.oldMethod
  • 他覆盖了oldMethod(),以便能够添加更多内容
【解决方案3】:

您可以使用 AspectJ 和 ajc 编译器尝试以下操作。

// Class1Extensions.aj
aspect Class1Extensions {
    // An inter-type declaration
    public void Class1.newMethod() {
       //...
    }
}

您需要使用ajc 进行编译,这样调用object1.newMethod() 的代码就不会反叛。您还可以为newMethod 创建一个接口并放入该方面:

declare parents Class1+ implements Class1NewMethods;

然后,你可以写

Class1NewMethods object2 = (Class1NewMethods) object1;
object2.newMethod();

【讨论】:

    【解决方案4】:

    我认为你应该去继承。细化 zerocool 的注释,可以声明 Class2 扩展 Class1。

    Class Class1{
        public void methodx(){
    
        }
    }
    
    class Class2 extends Class1{
        public void extraMethod(){
    
        }
    
    }
    

    那你还可以有一个

    Class1 obj = new Class2();
    

    这将为您提供一个带有 Class1 引用的 Class2 obj。

    如果你真的想要一个从 Class2 到 Class1 的数据转换器,你可以编写一个 Class2 的重载构造函数,它接受一个 Class1 对象,如下所示:

    public Class2 (Class1 obj)
    {
        this.setName(obj.getName()); //Assuming name attribute
        ... // and other setter methods
    }
    

    编辑:

    作为包装器,您可以执行以下操作:

    public class Class2
    {
        private Class1 obj;
    
        public Class1 getClass1Obj()
        {
            return obj;
        }
    
        public void newMethod()
        {
            // your method here
        }
    }
    

    旧方法可以在getClass1Obj()返回的对象上调用,直接在Class2的对象上调用newMethod()

    【讨论】:

    • 感谢您的回答。你很接近,我的确切问题是如何避免这些setName 方法。我不想生成超过 100 个 setter。
    • 感谢您的编辑,但不幸的是,由于 Class2 不再扩展 Class1,因此我无法使用包装类对象代替原始对象。
    【解决方案5】:
    Class Class1{
        public void methodx(){
    
        }
    }
    
    class Class2 extends Class1{
        public void extraMethod(){
    
        }
    
    }
    

    继承是完美的案例。这里methodx 将被继承,其行为与class1 中定义的完全相同,在class2 中,您可以定义一个特定于class2 的新行为。

    【讨论】:

    • 如何将 object1 传递给 Class2 以获得具有完全相同行为但 extraMethod 的 object2?如果我不能这样做,那么 object2 对我没有用。
    • 我现在明白你的问题了。这是给你的问题:即使这个对象来自第三方,你认为你可以在没有类的情况下引用它吗?类 1 对象 1;这里你将如何编译这段代码,除非你有 Class1 或任何其他超类型 Class1
    猜你喜欢
    • 2017-07-14
    • 1970-01-01
    • 2010-10-12
    • 2017-11-30
    • 1970-01-01
    • 2014-01-14
    • 1970-01-01
    • 2011-09-07
    • 1970-01-01
    相关资源
    最近更新 更多