在工作中,我正在执行此应用程序,该应用程序从外部文件(Excel工作表,文本文件......)中获取值,并将这些值转换为复杂的指令,并将其输入到另一个系统中。
下面的代码有点简化(没有指令和非常简单的逻辑),但这个想法保持不变。我有大约60个不同的翻译人员,他们背后有不同的业务逻辑。有些只运行一个参数。其他人则采取多种论点。
我有一个抽象的翻译班。该类的用户将使用2种公共方法: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();
}
}
Pro的:
我的问题:
我想过将Factory模式用于翻译器创建,但后来我不能在设计时使用属性作为参数提示。
所以我基本上在寻找一种解决方案,在设计时你可以很容易地看到需要哪些参数。同时我希望通过不让每个控制器都有30个新的xTranslator语句来减少耦合。
PS:我只限于使用.NET 3.5代码。
答案 0 :(得分:2)
different controller classes are using many translators. I have too much coupling
控制器类应仅依赖于抽象,即BaseTranslator
。因此,您将没有太多的耦合,实际上它将是松耦合代码。通过依赖注入(例如通过构造函数参数)将依赖项注入控制器。
使代码仅依赖于基类型的一个选项 - 在基类中创建字符串属性Text
:
BaseTranslator translator = new ReverseTranslator(); // inject implementation
translator.Text = "Stella";
translator.Translate();
translator.Text = "I'm not a beer";
translator.Translate();
答案 1 :(得分:0)
我觉得有些事情是矛盾的:
如果这是对的,我相信你没有为你的模型找到合适的抽象级别。换句话说,你当前的抽象根本没有帮助(或多或少),因为它在每个具体类中都有扩展。所以我的建议是首先看看模型本身(但这只是猜测,因为我不知道你的模型:-))。
如果您能够提供7-10个代表性具体类名称列表以及他们希望让我们更好地了解您的域名的输入值,那么这里的某人可能会更好地指导您。
答案 2 :(得分:0)
要获得具体类的特定参数的设计时信息: ,您需要使用具体类的实例。
要减少控制器中的耦合: ,您需要限制自己的抽象类实例。
你不能同时在同一个地方。
重新设计整体设计可以消除耦合并消除对设计时间信息的需求。
将转换器的创建和初始化从控制器移出到工厂或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
{
...
}