views:

499

answers:

1
// Enrich with is enriching more than i want

public intefrace ICommand {
   void Execute();
}

// classes

public class A : ICommand {}
public class B : ICommand {}
public class MultiCommand : ICommand {
  public MultiCommand(ICommand[] commands) {}
}

// -- decorators
public DecoratorOne : ICommand {
  public DecoratorOne(Icommand toDecorate) {}
}

public DecoratorTwo : ICommand {
  public DecoratorOne(Icommand toDecorate) {}
}



// what i tried

 ForREquesedType<ICommand>()
    .TheDefaultIsConcreteType<A>
    .EnrichWith(x => new DecoratorOne(x)
    .EnrichWith(y => new DecoratorTwo(y)
    .CacheBy(InstanceScope.Singleton);

 InstanceOf<ICommand>()
    .TheDefault.Is.OfConcreteType<B>
    .EnrichWith(x => new DecoratorOne(x)
    .WithName("secondCommand")

            ForRequestedType<MultiCommand>()
                .TheDefault.Is.OfConcreteType<MultiCommand>()
                .TheArrayOf<ICommand>()
                .Contains(y =>
                              {
                                  y.TheDefault();
                                  y.TheInstanceNamed("secondCommand")
                              })
                .WithName("multi");

**

/// what i want to do

**

What i want is that A is the default. So anyplace that wants an instance of ICommand it will get A. MultiCommand will have both A and B and will execute them in a loop.

**

// the problem i'm having

**

B seems to be decorated a few times. When i call ObjectFactory.GetNamedInsance<ICommand>("secondCommand") i'm getting something along the lines of new **new DecoratorOne(new DecorateOne(B)).** I'm assuming it's being decorated because of the definition i have for the default, A. How can i avoid this?

Also is that the proper way to inject the array into multicommand?

Thanks again, i'm new to structure map so any help would be appreciated.

UPDATE

What i ended up doing was creating a subclass of TypeInterceptor which decorated the types appropriately. This doesn't feel right to me but it's better than using 'new' throughout my code. So the code turned into

        RegisterInterceptor(new CommandDecoratorInterceptor());

        // this is the default that everyone hooks into
        ForRequestedType<ICOmmand>()
            .TheDefaultIsConcreteType<A>()
            .CacheBy(StructureMap.Attributes.InstanceScope.Singleton);

        InstanceOf<ICommand>()
            .Is.OfConcreteType<B>()
            .WithName("secondCommand");


        ForRequestedType<MultiCommand>()
            .TheDefault.Is.OfConcreteType<MultiCommand>()
            .TheArrayOf<ICommand>()
            .Contains(y =>
                          {
                              y.TheDefault();
                              y.TheInstanceNamed("secondCommand");
                          });

And then the new Type interceptor decorates the classes as before. This allows the MultiMonitor to avoid being decoreated(Enriched).

Any suggestions on improving this would be appreciated ;)

+2  A: 

Don't use TheDefaultIsConcreteType before enrich. That would be just like doing it right after ForRequestedType(), which is saying you want to enrich all ICommands. Use TheDefault.Is.OfConcreteType instead.

Also don't double Enrich, it doesn't chain well when replacing instances. The following should work for your scenario:

    ForRequestedType<ICommand>()
        .CacheBy(StructureMap.Attributes.InstanceScope.Singleton)
        .TheDefault.Is.OfConcreteType<A>()
        .EnrichWith(x => new DecoratorTwo(new DecoratorOne(x)));
    InstanceOf<ICommand>().Is
        .OfConcreteType<B>()
        .EnrichWith(x => new DecoratorOne(x))
        .WithName("second");
    InstanceOf<ICommand>().Is
        .OfConcreteType<MultiCommand>()
        .TheArrayOf<ICommand>().Contains(y =>
        {
            y.TheDefault();
            y.TheInstanceNamed("second");
        })
        .WithName("multi");
eglasius
thanks. That passes my tests. -- side note: This isn't the case right now but what if i wanted B to be InstanceScope.PerRequest ? --thanks again
hdz