繁体   English   中英

关于工厂设计架构的问题

[英]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的接口ICalculableIAlgorithm ?),你可以调用它:

ICalculable calculable = obj as ICalculable;
if ( calculable != null ) calculable.Calculate();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM