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

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

问题描述

根据登录用户的类型,我的 Web 应用程序在业务逻辑和表示逻辑方面有一些细微的变化.似乎通过基于用户类型注入不同的具体类来获得变化非常适合 DI.所以我想知道我应该使用 StructureMap 的哪些功能来实现这一点(或者如果我偏离了 DI 的目的).

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).

(我刚刚了解到 Profiles 不是实现此目的的方法,因为设置 Profile 不是每个线程的操作:StructureMap 配置文件线程安全吗?)

(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?)

这是解决这个问题的方法吗?

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"));
    }
}

推荐答案

实现这一点的一种常用方法是 Mark 所描述的.您有一个类接受所有具体实例的数组(它必须是一个数组,StructureMap 才能按预期运行),然后使用一些逻辑来确定要使用哪个实例.

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

这取决于以下类型:

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天全站免登陆