使用StructureMap实现策略模式的最佳方式 [英] Best way to use StructureMap to implement Strategy pattern

查看:205
本文介绍了使用StructureMap实现策略模式的最佳方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的网络应用程序在业务逻辑和表示逻辑方面有一些微小的变化,具体取决于登录用户的类型。通过根据用户类型注入不同的具体类似于获取变体是非常适合DI的。所以我想知道StructureMap我应该使用什么功能来实现这一点(或者如果我基于DI的目的)。



(我刚刚了解到,配置文件不是完成此操作的方法,因为设置配置文件不是每个线程的操作:结构图配置文件线程安全?



编辑



这是这个方式吗?

  public class HomeController 
{
private ISomeDependancy _someDependancy;

public HomeController(ISomeDependancy someDependancy)
{
_someDependancy = someDependancy;
}

public string GetNameFromDependancy()
{
return _someDependancy.GetName();
}
}

public interface ISomeDependancy
{
string GetName();


public class VersionASomeDependancy:ISomeDependancy
{
public string GetName()
{
返回我的名字是版本A;



public class VersionBSomeDependancy:ISomeDependancy
{
public string GetName()
{
returnMy Name是版本B;
}


public class VersionARegistry:Registry
{
public VersionARegistry()
{
// build up complex graph here
ForRequestedType< ISomeDependancy>().DefaultIsConcreteType< VersionASomeDependancy>();
}
}

public class VersionBRegistry:Registry
{
public VersionBRegistry()
{
// build up complex graph here
ForRequestedType< ISomeDependancy>().DefaultIsConcreteType< VersionBSomeDependancy>();
}


public class ContainerA:Container
{
public ContainerA()
:base(new VersionARegistry())
{
}
}

public class ContainerB:Container
{
public ContainerB()
:base(new VersionBRegistry )
{
}
}

[TestFixture]
public class线束
{
[测试]
public void ensure_that_versions_load_based_on_named_containers()
{
ObjectFactory.Initialize(c =>
{
c.ForRequestedType< IContainer>()。AddInstances(
x =>
{
x.OfConcreteType< ContainerA>()。WithName(VersionA);
x.OfConcreteType< ContainerB>()。WithName(VersionB);
}) .CacheBy(InstanceScope.Singleton);
});

HomeController控制器;

IContainer containerForVersionA = ObjectFactory.GetNamedInstance< IContainer>(VersionA);
controller = containerForVersionA.GetInstance< HomeController>();
Assert.That(controller.GetNameFromDependancy(),Is.EqualTo(My Name is Version A));

IContainer containerForVersionB = ObjectFactory.GetNamedInstance< IContainer>(VersionB);
controller = containerForVersionB.GetInstance< HomeController>();
Assert.That(controller.GetNameFromDependancy(),Is.EqualTo(My Name is Version B));
}
}


解决方案

正如马克所描述的,实现这一点的常用方法。你有一个类接收所有具体实例的数组(它必须为StructureMap的数组,按预期的行为),然后使用一些逻辑来计算出要使用的实例。 >

您可以将一些示例代码粘贴到控制台程序或单元测试中:

  var container = new Container(x => x.Scan(scan => 
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.AddAllTypesOf< ; IDiscountCalculator>();
}));
var strategy = container.GetInstance< IDiscountStrategy>();
Console.WriteLine(strategy.GetDiscount(Regular,10)); // 0
Console.WriteLine(strategy.GetDiscount(Normal,10)); // 1
Console.WriteLine(strategy.GetDiscount(Special,10)); // 5

这取决于以下类型:

  public interface IDiscountStrategy 
{
decimal GetDiscount(string userType,decimal orderTotal);
}

public class DiscountStrategy:IDiscountStrategy
{
private readonly IDiscountCalculator [] _discountCalculators;

public DiscountStrategy(IDiscountCalculator [] discountCalculators)
{
_discountCalculators = discountCalculators;


public decimal GetDiscount(string userType,decimal orderTotal)
{
var calculator = _discountCalculators.FirstOrDefault(x => x.AppliesTo(userType)) ;
if(calculator == null)return 0;
return calculator.CalculateDiscount(orderTotal);
}
}

public interface IDiscountCalculator
{
bool AppliesTo(string userType);
decimal CalculateDiscount(decimal orderTotal);
}

public class NormalUserDiscountCalculator:IDiscountCalculator
{
public bool AppliesTo(string userType)
{
return userType ==Normal ;
}

public decimal CalculateDiscount(decimal orderTotal)
{
return orderTotal * 0.1m;
}
}

public class SpecialUserDiscountCalculator:IDiscountCalculator
{
public bool AppliesTo(string userType)
{
return userType ==特别
}

public decimal CalculateDiscount(decimal orderTotal)
{
return orderTotal * 0.5m;
}
}


My web app has some slight variations in business logic and presentation logic depending on the type of user that is logged in. It seems like getting variations by injecting different concrete classes based on the user type is a good fit for DI. So I'm wondering what features of StructureMap I should use to achieve this (or if I'm way off base on the purposes of DI).

(I just learned that Profiles are not the way to accomplish this because setting the Profile isn't a per-thread operation: Are StructureMap profiles thread safe?)

EDIT

Is this the way to go about this?

public class HomeController
{
    private ISomeDependancy _someDependancy;

    public HomeController(ISomeDependancy someDependancy)
    {
        _someDependancy = someDependancy;
    }

    public string GetNameFromDependancy()
    {
        return _someDependancy.GetName();
    }
}

public interface ISomeDependancy
{
    string GetName();
}

public class VersionASomeDependancy : ISomeDependancy
{
    public string GetName()
    {
        return "My Name is Version A";
    }
}

public class VersionBSomeDependancy : ISomeDependancy
{
    public string GetName()
    {
        return "My Name is Version B";
    }
}

public class VersionARegistry : Registry
{
    public VersionARegistry()
    {
        // build up complex graph here
        ForRequestedType<ISomeDependancy>().TheDefaultIsConcreteType<VersionASomeDependancy>();
    }
}

public class VersionBRegistry : Registry
{
    public VersionBRegistry()
    {
        // build up complex graph here
        ForRequestedType<ISomeDependancy>().TheDefaultIsConcreteType<VersionBSomeDependancy>();
    }
}

public class ContainerA : Container
{
    public ContainerA()
        : base(new VersionARegistry())
    {
    }
}

public class ContainerB : Container
{
    public ContainerB()
        : base(new VersionBRegistry())
    {
    }
}

[TestFixture]
public class Harness
{
    [Test]
    public void ensure_that_versions_load_based_on_named_containers()
    {
        ObjectFactory.Initialize(c =>
        {
            c.ForRequestedType<IContainer>().AddInstances(
                x =>
                {
                    x.OfConcreteType<ContainerA>().WithName("VersionA");
                    x.OfConcreteType<ContainerB>().WithName("VersionB");
                }).CacheBy(InstanceScope.Singleton);
        });

        HomeController controller;

        IContainer containerForVersionA = ObjectFactory.GetNamedInstance<IContainer>("VersionA");
        controller = containerForVersionA.GetInstance<HomeController>();
        Assert.That(controller.GetNameFromDependancy(), Is.EqualTo("My Name is Version A"));

        IContainer containerForVersionB = ObjectFactory.GetNamedInstance<IContainer>("VersionB");
        controller = containerForVersionB.GetInstance<HomeController>();
        Assert.That(controller.GetNameFromDependancy(), Is.EqualTo("My Name is Version B"));
    }
}

解决方案

One common way to implement this is as Mark described. You have a class that takes in an array of all concrete instances (it must be an array for StructureMap to behave as expected), and then uses some logic to figure out which instance to use.

Some sample code you can paste into a console program or unit test:

var container = new Container(x => x.Scan(scan =>
{
    scan.TheCallingAssembly();
    scan.WithDefaultConventions();
    scan.AddAllTypesOf<IDiscountCalculator>();
}));
var strategy = container.GetInstance<IDiscountStrategy>();
Console.WriteLine(strategy.GetDiscount("Regular", 10)); // 0
Console.WriteLine(strategy.GetDiscount("Normal", 10)); // 1
Console.WriteLine(strategy.GetDiscount("Special", 10)); // 5

which depends on the following types:

public interface IDiscountStrategy 
{
    decimal GetDiscount(string userType, decimal orderTotal);
}

public class DiscountStrategy : IDiscountStrategy
{
    private readonly IDiscountCalculator[] _discountCalculators;

    public DiscountStrategy(IDiscountCalculator[] discountCalculators)
    {
        _discountCalculators = discountCalculators;
    }

    public decimal GetDiscount(string userType, decimal orderTotal)
    {
        var calculator = _discountCalculators.FirstOrDefault(x => x.AppliesTo(userType));
        if (calculator == null) return 0;
        return calculator.CalculateDiscount(orderTotal);
    }
}

public interface IDiscountCalculator
{
    bool AppliesTo(string userType);
    decimal CalculateDiscount(decimal orderTotal);
}

public class NormalUserDiscountCalculator : IDiscountCalculator
{
    public bool AppliesTo(string userType)
    {
        return userType == "Normal";
    }

    public decimal CalculateDiscount(decimal orderTotal)
    {
        return orderTotal * 0.1m;
    }
}

public class SpecialUserDiscountCalculator : IDiscountCalculator
{
    public bool AppliesTo(string userType)
    {
        return userType == "Special";
    }

    public decimal CalculateDiscount(decimal orderTotal)
    {
        return orderTotal * 0.5m;
    }
}

这篇关于使用StructureMap实现策略模式的最佳方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆