Круговая ссылка весной с составным рисунком - PullRequest
3 голосов
/ 21 декабря 2011

допустим, у меня есть такая структура: Composite Pattern

Как вы можете видеть, это сложный паттерн.Как создать экземпляр этого шаблона с помощью Spring?Например, если у меня есть следующий код:

<bean id="leaf1">
   <constructor-arg name="Name" value="leaf1" />
</bean>
 <bean id="leaf2">
   <constructor-arg name="Name" value="leaf2" />
</bean>
<bean id="leaf3">
   <constructor-arg name="Name" value="leaf3" />
</bean>
<bean id="composite1">
    <constructor-arg>
        <set>
            <ref bean="composite2" />
            <ref bean="leaf2" />
        </set>
    </constructor-arg>
</bean>
<bean id="composite2">
    <constructor-arg>
        <set>
            <ref bean="leaf3" />
                         <ref bean="leaf1" /> 
        </set>
    </constructor-arg>
</bean>

Как вы можете видеть здесь, эта конфигурация будет повышаться и org.springframework.beans.factory.BeanCreationException из-за циклической ссылки.Композит содержит список Компонентов, а компонент состоит из Листа и Композита.Как мне решить эту проблему с помощью Spring?

Ответы [ 2 ]

3 голосов
/ 21 декабря 2011

Ответ на этот тип проблемы не зависит от пружины и тот же, если вы кодировали это в прямой Java, используя обычные конструкторы.

Простое решение состоит в том, чтобы разрешить настройку вашего композита с использованием инжектора сеттера, чтобы он нарушил цикл ссылок, необходимых при построении, но это умаляет идеализм инжекции конструктора. Альтернативой является создание подкласса Composite, который делегирует другому Composite. Это позволит вам заполнить фактическую ссылку позже, хотя и не идеально, но вы можете использовать метод spring @postContstruct, чтобы проверить, что ссылка действительно установлена, что обеспечивает такие же гарантии, как при использовании обычного конструктора.

Существуют фреймворки, которые автоматически обрабатывают этот круговой конструктор (например, наноконтейнер ), вводя прокси, но на самом деле это просто скрывает запах дизайна с временным освежителем. В конечном счете, вам нужно двухэтапное построение для достижения этой цели - это невозможно с чистыми конструкторами в java, поскольку для прерывания цикла зависимостей требуется использование неконструктивного инициализатора.

Написание функциональных тестов для этих классов, работающих вместе, может помочь выделить проблему проектирования с другой точки зрения.

1 голос
/ 21 декабря 2011

Я думаю, что это должен быть тот Композитный Компонент IS-A, который не состоит из Листа и Композита. Составной должен иметь коллекцию экземпляров компонентов.

public interface Component {
    void operation();
}

public class Leaf implements Component {
    public void operation() { System.out.println("I'm a Leaf"); }
}

public class Composite implements Component {
    private Collection<Component> components;

    public Composite() {
        this(new ArrayList<Component>());
    }

    public Composite(Collection<Component> components) {
        this.components =  = new ArrayList<Component>(components);
    }

    public void operation() { 
        System.out.println("I'm a Composite"); 
        for (Component component : this.components) {
            component.operation();
        }
    }
    public void addComponent(Component c) { this.components.add(c); }
    public void removeComponent(Component c) { this.components.remove(c); }
}
...