在工作中,我正在做这个应用程序,它从外部文件(Excel 工作表、文本文件等)中获取值,并将这些值转换为复杂的指令,然后输入到另一个系统中。

下面的代码有点简化(没有指令和非常简单的逻辑),但想法保持不变。我有大约 60 个不同的翻译器,它们背后运行着不同类型的业务逻辑。有些人只需要一个参数就可以运行。其他人采取多个论点。

我有一个抽象翻译课。该类的用户将使用 2 个公共(public)方法:Translate 运行翻译逻辑,CanTranslate 允许查看翻译器是否准备好启动。

使用这个抽象类的开发人员需要实现包含实际业务逻辑的 DoTranslate 方法。默认情况下 CanTranslate 总是返回 true 但如果需要验证它可以被覆盖。

这是抽象翻译器基类:

// Contains some base logic which is the same for all translators
public abstract class BaseTranslator
{
    // Public translate method
    public void Translate()
    {
        if (CanTranslate())
            DoTranslate();
    }

    // Checks if we are ready to translate
    // True by default
    public virtual bool CanTranslate()
    {
        return true;
    }

    // This method is used to implement business logic
    public abstract void DoTranslate();
}

这是一个具体的翻译器类的实现:
// Translates beer names
public class ReverseTranslator : BaseTranslator
{
    // Use of properties to allow strongly typed arguments
    // which can be seen by the developer at design time
    public string BeerName { get; set; }

    // Validation
    public override bool CanTranslate()
    {
        if (BeerName.Equals("Budweiser") || BeerName.Equals("Stella"))
            return true;
        else
            return false;
    }

    // Implementation of the business logic
    public override void DoTranslate()
    {
        char[] letters = BeerName.ToCharArray();
        Array.Reverse(letters);
        Console.WriteLine(new string(letters));
    }
}

这是使用时的样子:
class Program
{
    public static void Main(string[] args)
    {
        var translator = new ReverseTranslator();

        translator.BeerName = "Stella";
        translator.Translate();

        translator.BeerName = "I'm not a beer";
        // This line will not translate since it's not a valid beer name.
        translator.Translate();

        Console.ReadLine();
    }
}

亲:
  • 在小的可维护单元中分离特定的业务逻辑
  • 转换器很容易在应用程序的其他部分重用
  • 翻译器可以很容易地进行单元测试
  • 属性允许翻译器的用户查看需要哪些参数

  • 我的问题:
  • 不同的 Controller 类使用了许多转换器。我有太多的耦合。

  • 我想过使用工厂模式来创建翻译器,但后来我不能在设计时使用属性作为参数提示。

    所以我基本上是在寻找一种解决方案,在该解决方案中,您可以在设计时轻松查看需要哪些参数。同时我希望通过不让每个 Controller 有 30 个新的 xTranslator 语句来减少耦合。

    PS:对于此代码,我只能使用 .NET 3.5。

    最佳答案

    要获得具体类的特定参数的设计时信息: 您需要使用具体类的实例。
    为了减少 Controller 中的耦合: 你需要限制抽象类的实例。
    你不能同时在同一个地方拥有两者。

    重新设计整体设计可以消除耦合并消除对设计时间信息的需求。

    将转换器的创建和初始化从 Controller 移到工厂或 IoC 容器中,该容器将外部文件中的一行数据作为输入(如果需要,可以将其按摩为可以使用的格式)。

    让翻译器需要一个接受参数集合的构造函数。
    好处:

  • 只有具体类本身需要知道关于它自己或
    它的参数。
  • 工厂需要有关在何种情况下使用哪个翻译器的信息。

  • .
    class TranslatorFactory
    {
        //translator lookup table
        private Dictionary<string, Func<List<string>,BaseTranslator>> Translators =
            new Dictionary<string,Func<List<string>,BaseTranslator>>{
                {"Reverse", (args)=>new ReverseTranslator(args)},
                {"Explode", (args)=>new ExplodeTranslator(args)}        };
    
        public BaseTranslator GetTranslatorForRow(string command, List<string> arguments)
        {
            if(Translators.ContainsKey(command) )
            {
                 return Translators[command](arguments);
            }
            return null; //or default, or throw exception
        }
    }
    
    
    abstract class BaseTranslator
    {
        ...
        public BaseTranslator(List<string> args)
        {
        }
    }
    
    class ReverseTranslator: BaseTranslator
    {
        public string BeerName {get;set;}
        public ReverseTranslator(List<string> args)
        {
            BeerName = args[0];
        }
    }
    

    您可以更进一步,使用属性和反射来动态构建查找表,消除工厂和具体类之间的耦合。
    [TranslatorFor("Reverse")]
    class ReverseTranslator: BaseTranslator
    {
        ...
    }
    

    关于c# - 如何减少此代码中的耦合,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13593784/

    10-09 09:43