在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之类的更简单的机制。继承的一个问题是它暴露了父级的所有方法,而我想指定哪些方法在子级中实际可用,所以可能只是一个单独的类?
答案 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
的源代码。
我对该系列的看法
HashMap
。java.util
集合接口
答案 2 :(得分:0)
看起来您正在尝试实现类似于CSS的行为 - 尤其是 Cascading 部分。这不是一个特别常见的模式,但我之前必须实现这种方式。 IMO,我不会将类型拆分为Foo
和FooInstance
- 我会创建一个通常使用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;
}
}