实现另一个对象

时间:2010-11-10 21:52:34

标签: java inheritance instance

在java中,我可能有一个对象 a ,其中包含一些属性,如getColor。然后,我可能会创建第二个对象 b (可能是同一个类),其行为类似于对象 a ,因为它与 a <做同样的事情/ em>除非其中一个值被特别更改(并且也未更改)。

a = new Foo()
b = new FooWhichRefersToAnotherFoo(a)

a.getColor() # returns blue
b.getColor() # returns blue
a.setColor(red)
b.getColor() # returns red
b.setColor(pink)
b.getColor() # returns pink
a.getColor() # returns red (unchanged)
b.deleteChangeToColor()
b.getColor() # returns red as it is now pointing back to a

我认为它会是某种树层次结构,好像我有 c 指向 b 指向 a ,对象会将链处理到第一个指定值或原始未显示对象的默认值。

这样的模式是否与java兼容?我希望第一个类是一个类,第二个类是一个继承类,它跟踪它实例化的类,如果没有设置它自己的属性,则查询父对象。

我想我可以自己做每个班级,我可以创建一个单独的类,如

class Foo {
  Color color = new Color("red");
  Color getColor() { color }
}

class FooInstance extends Foo {
  Foo parent = null;

  FooInstance(Foo parent) {
    this.parent = parent;
  }

  Color getColor() {
    if (color == null) return parent.getColor();
    else return color;
  }
}

但是想确保没有像使用javabeans之类的更简单的机制。继承的一个问题是它暴露了父级的所有方法,而我想指定哪些方法在子级中实际可用,所以可能只是一个单独的类?

4 个答案:

答案 0 :(得分:1)

我已经阅读了你的帖子了几次,有些事情仍然让我感到困惑。例如,在a / b / c示例中,除非值不同,否则您谈论的行为是相同的。我认为你需要更清楚地分离行为和状态的概念。行为是一个类将要做的事情,声明它是它的属性的值。一个类的行为如果经常依赖于状态,即:

Color getColor() {
    if (color == null) return parent.getColor();
    else return color;
}

但它们是两回事。从您的示例中我不认为您需要两个或更多不同的类。您可以将Foo和FooInstance重新编码为单个类,如下所示:

class Foo {
    Foo parent = null;
    Color color;

    Foo(Foo parent) {
        this.parent = parent;
    }

    Color getColor() {
        //If there is no parent we have to return color regardless.
        if (parent == null) {
            return color;
        }

        // If there is a parent we can choose which to return.
        return color == null ? parent.getColor() : color;
    }

    void setColor(Color color) {
        this.color = color;
    }
}

除非您需要与FooInstance不同的行为,否则您可以通过单个课程完成所需的操作。

我不知道提供此类数据结构的任何第三方API。但它们可能存在。

答案 1 :(得分:1)

有一个鲜为人知的feature java.util.Properties,允许您创建此类层次结构而无需特殊代码:

package stackoverflow;
import java.util.Properties;

public class Main {
    static Properties propsBase;
    static Properties propsOverlay;
    static Properties propsOverlayOverlay;

    public static void main(String[] args) {
        propsBase = new Properties();
        propsOverlay = new Properties(propsBase);
        propsOverlayOverlay = new Properties(propsOverlay);

        propsBase.setProperty("key1", "value1");
        propsBase.setProperty("key2", "value2");
        debugAllProps();

        propsOverlay.setProperty("key1", "overlayValue1");
        debugAllProps();

        propsOverlayOverlay.setProperty("key1", "overlayOverlayValue1");
        debugAllProps();

        propsOverlayOverlay.remove("key1");
        debugAllProps();

        propsOverlay.remove("key1");
        debugAllProps();
    }

    private static void debugAllProps() {
        printProps("propsBase", propsBase);
        printProps("propsOverlay", propsOverlay);
        printProps("propsOverlayOverlay", propsOverlayOverlay);
        System.out.println("------------------------------------------------");
    }

    private static void printProps(String desc, Properties props) {
        System.out.printf("%-25s", desc + " sees:");
        for (String key : props.stringPropertyNames()) {
            System.out.printf(" %s=%s", key, props.getProperty(key));
        }
        System.out.println();
    }
}


输出:

propsBase sees:           key2=value2 key1=value1
propsOverlay sees:        key2=value2 key1=value1
propsOverlayOverlay sees: key2=value2 key1=value1
-------------------------------------------------
propsBase sees:           key2=value2 key1=value1
propsOverlay sees:        key2=value2 key1=overlayValue1
propsOverlayOverlay sees: key2=value2 key1=overlayValue1
-------------------------------------------------
propsBase sees:           key2=value2 key1=value1
propsOverlay sees:        key2=value2 key1=overlayValue1
propsOverlayOverlay sees: key2=value2 key1=overlayOverlayValue1
-------------------------------------------------
propsBase sees:           key2=value2 key1=value1
propsOverlay sees:        key2=value2 key1=overlayValue1
propsOverlayOverlay sees: key2=value2 key1=overlayValue1
-------------------------------------------------
propsBase sees:           key2=value2 key1=value1
propsOverlay sees:        key2=value2 key1=value1
propsOverlayOverlay sees: key2=value2 key1=value1

这种方法有一些重要的限制:

  • 因为这是java.util.Properties,您只能存储和检索String值。

  • 您必须小心只使用java.util.Properties定义的访问器方法,因为其超类Hashtable定义的方法不了解层次结构而忽略它。 / p>

如果我正在做任何严肃的事情,我可能不会使用java.util.Properties,而是使用Properties的一般方法作为灵感来设计我自己的集合。您可以通过查看随JDK一起安装的java.util.Properties来阅读src.zip的源代码。

我对该系列的看法

  • 允许对象键和对象值
  • 拥有允许检查和修改层次结构链的方法
  • 可能不会将任何现有集合子类化 - 主要是为了避免必须使每个超类方法“层次感知”。可能更像decorate一个HashMap
  • 如果
  • 有意义,可以实现一些java.util集合接口
  • 可能支持泛型

答案 2 :(得分:0)

看起来您正在尝试实现类似于CSS的行为 - 尤其是 Cascading 部分。这不是一个特别常见的模式,但我之前必须实现这种方式。 IMO,我不会将类型拆分为FooFooInstance - 我会创建一个通常使用HashMap来处理此模式的类对于属性值。通过这种方式,您可以自动处理null case并冒泡到父级。类似的东西:

public class Foo {
    private Foo parent;
    private HashMap<string, Object> propertyValues = new HashMap<string, Object)>();

    public Foo() {
    }

    public Foo(Foo parent) {
        this.parent = parent;
    }

    protected Object getProperty(string propertyName) {
        if (properties.containsKey(propertyName))
            return properties.get(propertyName);
        else if (parent != null)
            return parent.getProperty(propertyName);
        else
            return null;
    }

    protected void setProperty(string propertyName, value) {
        properties.put(propertyName, value);
    }

    public Color getColor() {
        return (Color)getProperty("color");
    }

    public void setColor(Color color) {
        setProperty("color", color);
    }
}

答案 3 :(得分:0)

我会用装饰模式做这件事。这两个类不一定需要相同,但需要实现一个公共接口,并在构造函数中接受另一个接口,然后让getter移交给包装类,直到在包装中重写一个类。在这个例子中,我只使用了一个类来简化,但可以灵活地使用任何Colorful。从测试开始:

import junit.framework.TestCase;

import java.awt.*;

public class CascadingTest extends TestCase {

    public void testCascade() throws Exception {
        Colorful a = new Foo();
        a.setColor(Color.RED);
        assertEquals(Color.RED, a.getColor());

        Colorful b = new Foo(a);
        assertEquals(Color.RED, b.getColor());

        b.setColor(Color.PINK);
        assertEquals(Color.PINK, b.getColor());

        b.setColor(null);
        assertEquals(Color.RED, b.getColor());
    }
}

import java.awt.*;

public interface Colorful {
    Color getColor();
    void setColor(Color color);
}

import java.awt.*;

public class Foo implements Colorful {

    private Color color;
    private Colorful parent;

    public Foo() {}

    public Foo(Colorful parent) {
        this.parent = parent;
    }

    public Color getColor() {
        if (parent != null && this.color == null) {
            return parent.getColor();
        } else {
            return color;
        }
    }

    public void setColor(Color color) {
        this.color = color;
    }
}