[英]Question about Factory Design Architecture
考虑这个例子
界面
interface IBusinessRules
{
string Perform();
}
继承人
class Client1BusinessRules: IBusinessRules
{
public string Perform()
{
return "Business rule for Client 1 Performed";
}
}
class Client2BusinessRules: IBusinessRules
{
public string Perform()
{
return "Business rule for Client 2 Performed";
}
}
class Client3BusinessRules: IBusinessRules
{
public string Perform()
{
return "Business rule for Client 3 Performed";
}
}
工厂类
class BusinessRulesFactory
{
public IBusinessRules GetObject(int clientIdentityCode)
{
IBusinessRules objbase = null;
switch (clientIdentityCode)
{
case 1:
objbase = new Client1BusinessRules();
break;
case 2:
objbase = new Client2BusinessRules();
break;
case 3:
objbase = new Client3BusinessRules();
break;
default:
throw new Exception("Unknown Object");
}
return objbase;
}
}
样品用量:
class Program
{
static void Main(string[] args)
{
BusinessRulesFactory objfactory = new BusinessRulesFactory ();
IBusinessRulesFactory objBase = objfactory.GetObject(2);
Console.WriteLine(objBase.Perform());
objBase = objfactory.GetObject(3);
Console.WriteLine(objBase.Perform());
Console.Read();
}
}
我的问题是,我如何在ALgorithm1类上添加另一个方法但不在界面中添加,因为我只是在特殊情况下使用它?
class Client1BusinessRules: IBusinessRules
{
public string Perform()
{
return "Client1 Business rules is Performed";
}
public string Calculate()
{
return "Additional functionality for CLient1";
}
}
我怎么想在UI上调用这样的东西
objBase = objfactory.GetObject(1);
Console.WriteLine(objBase.Calculate());
还有其他解决方案吗? 提前致谢
编辑:我重写它类似于我目前的项目设计
工厂模式的重点是返回合同的正确实现,以便消费者不必担心如何实例化它,而只是调用它的方法。 你总是可以测试实际的类型,强制转换它并调用方法,但这是一个非常糟糕的设计,我不推荐它。 消费者不应该对实际类型有任何了解。 您需要重新考虑您的设计。
我认为你正在使用工厂类来:
IBusinessRules
实际实现IBusinessRules
因此,我会通过引入新的界面来解决您的问题
interface IComputableRules : IBusinessRules
{
string Calculate();
}
只要您遵循基于接口的设计,将实际实例转换为与IBusinessRules
不同的接口就没有错。
IBusinessRules businessRule = objFactory.GetObject(...some input...)
...
// check if the computable service is supported and print the result
IComputableRules computable = businessRule as IComputableRules;
if (computable)
{
Console.WriteLine(computable.Calculate());
}
在这里,您可以将业务规则类视为服务提供者,保证一些基本服务,以及可选的附加服务,具体取决于业务规则的性质。
注意:通过将BusinessRulesFactory
转换为泛型类,您可以将特定服务的指示作为工厂合同的一部分,并确保返回的业务规则实现将支持特定(否则是可选)服务。
class BusinessRulesFactory<TService> where TService : IBusinessRules
{
public TService GetObject(int clientIdentityCode)
{
// ... choose business rule in respect to both clientIdentityCode and TService
}
}
如果您不需要特定的附加服务,您只需使用IBusinessRules
作为实际的类型参数。
如果您想坚持当前的架构,可以引入新的接口声明
interface ICalculationRules
{
string Calculate();
}
现在让我们通过添加接口声明来修改Client1BusinessRules
:
class Client1BusinessRules: IBusinessRules, ICalculationRules
{
// everything remains the same
}
像这样修改你的调用代码:
var objBase = objfactory.GetObject(1);
Console.WriteLine(objBase.Calculate());
var calcBase = obj as ICalculationRules;
if (calcBase != null) calculable.Calculate();
维护含义:每次引入新界面时,都必须触摸所有调用代码。 由于您发布此代码放在UI代码中,这可能会变得非常混乱。
您介绍的每个接口都意味着对类的添加行为。 如果你有很多不同的行为,那么我上面的解决方案感觉不对,因为总是需要使用as
操作和条件执行方法。 如果你想坚持一些经典的设计模式,这种行为的可变性可以用装饰模式或策略模式来对抗。 它们可以与工厂模式顺利结合。
在这种情况下可以采用许多方法,它取决于您愿意为获得价值而花费的成本。
例如,您可以使用简单的铸造。 您将从工厂获取算法对象,将其转换为正确的(特定)算法对象,然后调用“计算”功能。
另一个选项 - 更通用的选项 - 也需要更多的代码 - 将在基类中提供查询机制,提供有关对象内可用功能的信息。 这有点类似于查询COM中的接口。
您需要问自己的重要问题是:1。您需要多少次才能实现特定功能? 2.有没有办法可以通过基类增加的多态性来解决问题? 3.派生对象的用户是否知道他们正在使用特定对象,或者您是否希望他们不知道实际类型?
一般来说,在这种情况下我个人所做的是从最简单的解决方案开始(在这种情况下,特定的转换和调用函数),然后在我有更多关于域的数据时返回并重构。 如果你对“臭臭代码”很敏感,那么你就会发现你的混乱太多了,你会把它重构成一个更好的解决方案。
我会像这样修改它
interface IBusinessRules
{
string Perform();
bool CanCalculate { get; }
string Calculate();
}
并添加一个抽象基类(可选,但建议进一步扩展)
public abstract class BusinessRules : IBusinessRules {
protected BusinessRules() {
}
protected virtual bool CanCalculateCore() {
return false; // Cannot calculate by default
}
protected virtual string CalculateCore() {
throw new NotImplementedException("Cannot calculate");
}
protected abstract string PerformCore();
#region IBusinessRules Members
public string Perform()
{
return PerformCore();
}
public bool CanCalculate
{
get { return CanCalculateCore(); }
}
public string Calculate()
{
return CalculateCore();
}
#endregion
}
所以呼叫站点现在看起来很整洁:
objBase = objfactory.GetObject(1);
if (objBase.CanCalculate) {
Console.WriteLine(objBase.Calculate());
}
扩展接口的一个大问题是,它不会给调用者提供任何你可能支持该接口的提示。
这是一个域建模问题,与您在问题域中的BusinessRule和IBase的含义有关。
什么是IBase
? 听起来应该叫做IBusinessRule
。 在这种情况下,Calculate在“业务规则”的上下文中意味着什么。 如果它在您的域中具有通用含义,则IBusinessRule
应该实现它,其他类也应该实现它,即使只是作为空方法。
如果它在你的域中没有通用含义,那么你的类应该实现另一个具有Calculate的接口ICalculable
( IAlgorithm
?),你可以调用它:
ICalculable calculable = obj as ICalculable;
if ( calculable != null ) calculable.Calculate();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.