создание экземпляра другого объекта - PullRequest
3 голосов
/ 11 ноября 2010

В Java у меня может быть объект a со множеством свойств, таких как getColor.Затем я мог бы создать второй объект b (возможно, того же класса), который ведет себя аналогично объекту a в том смысле, что он делает то же самое, что и a если только одно из его значений не было специально изменено (и тоже не изменено).

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 ]

1 голос
/ 11 ноября 2010

Я прочитал ваш пост пару раз, и в нем есть некоторые вещи, которые до сих пор меня смущают.Например, в вашем примере 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 голос
/ 11 ноября 2010

Существует малоизвестная функция из 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, не знают об иерархии ине обращайте на это внимания.

Если бы я делал что-то серьезное, я бы, вероятно, не использовал java.util.Properties, а скорее проектировал бы свою собственную коллекцию, используя общий подход Properties в качестве вдохновения.Вы можете прочитать исходный код в java.util.Properties, посмотрев в src.zip, который установлен вместе с JDK.

Мой взгляд на коллекцию будет

  • Разрешить ключи объекта и объектзначения
  • Имеют методы, которые позволяют проверять и модифицировать цепочку иерархии
  • Вероятно, не будут подклассы какой-либо существующей коллекции - в основном, чтобы избежать необходимости превращения каждого метода суперкласса в "иерархию".Скорее всего, decorate a HashMap.
  • Может быть реализовано несколько java.util интерфейсов коллекции, если имеет смысл
  • Может поддерживать универсальные шаблоны
0 голосов
/ 11 ноября 2010

Я бы просто сделал это с помощью шаблона Decorator. Эти два класса не обязательно должны быть одинаковыми, но должны будут реализовать общий интерфейс и перенести другой в конструктор, а затем позволить получателю передать обработанный класс (ы), пока один не будет переопределен в обертке учебный класс. В этом примере я использовал только один класс для простоты, но мог быть гибким для работы с любым 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;
    }
}
0 голосов
/ 11 ноября 2010

Похоже, вы пытаетесь реализовать поведение, похожее на CSS - особенно часть Cascading . Это не очень распространенная модель, но мне приходилось реализовывать подобные вещи раньше. IMO, я бы не разбивал тип на Foo и FooInstance - я бы создал один класс, который бы обрабатывал этот шаблон в общем виде, вероятно, используя HashMap для значений свойств. Таким образом, вы можете автоматически обрабатывать нулевой регистр и переходить к родительскому элементу. Что-то вроде:

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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...