Создание компонентов с круговыми связями с использованием Castle Windsor - PullRequest
2 голосов
/ 01 февраля 2012

Я реализую конечный автомат, где каждый класс представляет состояние.Каждое государство знает, в какие другие состояния оно может перейти, и это, естественно, приводит к круговым отношениям.(См. State Design Pattern ).

Для этого упрощенного примера я создаю два компонента, где первый компонент имеет ссылку на второй компонент, а второй компонент имеет ссылкук первому.

Проблема в том, что инфраструктура Windsor правильно устанавливает ссылки для первого созданного компонента, но не устанавливает ссылки для второго:

Вот два компонента:

// DefaultMouseHandler knows about NewLineMouseHandler
public class DefaultMouseHandler : MouseHandler
{
    public DefaultMouseHandler()
    {
    }

    public NewLineMouseHandler NewLineMouseHandler
    {
        get;
        set;
    }

    internal override MouseHandler LeftButtonDown(System.Windows.Input.MouseButtonEventArgs e)
    {
        return this.NewLineMouseHandler;
    }
}


// NewLineMouseHandler knows about DefaultMouseHandler
public class NewLineMouseHandler : MouseHandler
{
    public NewLineMouseHandler()
    {
    }

    public DefaultMouseHandler DefaultMouseHandler
    {
        get;
        set;
    }

    internal override MouseHandler LeftButtonUp(System.Windows.Input.MouseButtonEventArgs e)
    {
        return this.DefaultMouseHandler;
    }
}

Затем я регистрирую компоненты следующим образом:

_windsorContainer.Register(Classes.FromThisAssembly()
                                 .BasedOn<MouseHandler>()
                         );

Но при первой попытке создать DefaultMouseHandler:

  • DefaultMouseHandler
  • NewLineMouseHandler построен
  • NewLineMouseHandler установлен на DefaultMouseHandler

Но DefaultMouseHandler НЕ установлен наNewLineMouseHandler.

Можно ли считать это дефектом в Виндзорском замке?

Каков наилучший способ, чтобы два компонента ссылались друг на друга, при этом ни один из компонентов не знал о контейнере Windsor?

Ответы [ 2 ]

0 голосов
/ 01 февраля 2012

Решение, которое я придумал, заключается в использовании TypedFactoryFacility .

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

public interface IMouseHandlerFactory
{
    T CreateHandler<T>() where T : MouseHandler;
}

// In the registration code
_windsorContainer.AddFacility<TypedFactoryFacility>();
_windsorContainer.Register(Classes.FromThisAssembly()
                               .BasedOn<MouseHandler>(),
                           Component.For<IMouseHandlerFactory>()
                                    .AsFactory()
                          );

// The base class
public abstract class MouseHandler
{
    // Every mousehandler will create at least one other mouse handler
    // This is the factory that they will use for mouse handling creation
    // The property will be automatically set by the DI container
    public IMouseHandlerFactory MouseHandlerFactory { get; set; }

    // Methods the concrete implementations will override
    internal virtual MouseHandler LeftButtonDown(MouseButtonEventArgs e) { return this; }
    internal virtual MouseHandler LeftButtonUp(MouseButtonEventArgs e) { return this; }
}   

// The implementations
public class DefaultMouseHandler : MouseHandler
{
    internal override MouseHandler LeftButtonDown(MouseButtonEventArgs e)
    {
        return this.MouseHandlerFactory.CreateHandler<NewLineMouseHandler>();
    }
}

public class NewLineMouseHandler : MouseHandler
{
    internal override MouseHandler LeftButtonUp(MouseButtonEventArgs e)
    {
        return this.MouseHandlerFactory.CreateHandler<DefaultMouseHandler>();
    }
}
0 голосов
/ 01 февраля 2012

Я согласен с @sll, что это может быть признаком того, что дизайн может быть улучшен. С другой стороны, есть веские причины делать то, что вы делаете. Если вы никогда не разрешаете NewLineMouseHandler и он используется только как зависимость NewLineMouseHandler, просто установите зависимость вручную:

windsor.Register(Classes.FromThisAssembly()
                    .BasedOn<MouseHandler>()
                    .ConfigureFor<NewLineMouseHandler>(
                        h => h.OnCreate(
                            c =>
                                {
                                    var @default = (DefaultMouseHandler) c;
                                    @default.NewLineMouseHandler.DefaultMouseHandler = @default;
                                }))
    );
...