关于工厂设计架构的问题

发布于 2024-09-18 23:18:29 字数 2221 浏览 4 评论 0原文

考虑这个例子

接口

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

我该如何在用户界面上调用它,比如这样

 objBase = objfactory.GetObject(1);
 Console.WriteLine(objBase.Calculate());

还有其他解决方案吗?提前致谢

编辑:我重写它以类似于我当前的项目设计

Consider this example

The Interface

interface IBusinessRules
{
    string Perform();
}

The Inheritors

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

The factory class

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

sample usage:

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

My question is, how about I add another method on the ALgorithm1 Class
but not in the interface because im going to just use it on special scenario?

class Client1BusinessRules: IBusinessRules
{
    public string Perform()
    {
        return "Client1 Business rules is Performed";
    }


    public string Calculate()
    {
        return "Additional functionality for CLient1";
    }
}

how Am I suppose to call that on the UI something like this

 objBase = objfactory.GetObject(1);
 Console.WriteLine(objBase.Calculate());

Is there any other solution? thanks in advance

EDIT: I rewrite it to resemble my current project design

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

慈悲佛祖 2024-09-25 23:18:29

我假设您使用工厂类是为了:

  • 拥有一个标准外观,接受导致业务规则选择的参数配置
  • 封装业务规则配置
  • 将用户与 IBusinessRules 的实际实现分离code>

因此,我会通过引入新接口来解决您的问题

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 作为实际类型参数。

I presume you are using the factory class in order to:

  • have a standard facade accepting parameters that lead to business rule selection and provisioning
  • encapsulate business rule provisioning
  • decouple the users from actual implementations of IBusinessRules

Hence I would solve your problem by introducing new interface

interface IComputableRules : IBusinessRules
{
    string Calculate();
}

As long as you follow the interface-based design, there's nothing wrong about casting the actual instance to an interface different from 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());
}

Here you can think of you business rule classes as service providers, that guarantee some basic service, plus optional additional services depending on the nature of the business rule.

Note: By turning the BusinessRulesFactory into a generic class you might make the indication of a specific service a part of the factory contract, and make sure the returned business rule implementation will support a particular (otherwise optional) service.

class BusinessRulesFactory<TService> where TService : IBusinessRules
{
     public TService GetObject(int clientIdentityCode)
     {
         // ... choose business rule in respect to both clientIdentityCode and TService
     }
}

In case where you wouldn't require a specific additional service to be available, you'd just use IBusinessRules as the actual type parameter.

烟酉 2024-09-25 23:18:29

工厂模式的全部要点是返回合约的正确实现,以便消费者不必担心如何实例化它,而只需调用它的方法。您始终可以测试实际类型,转换为它并调用该方法,但这是一个非常糟糕的设计,我不会推荐它。消费者不应该知道任何关于实际类型的信息。您将需要重新考虑您的设计。

The whole point of the factory pattern is to return the proper implementation of a contract so that the consumer shouldn't worry about how to instantiate it but simply invoke its methods. You could always test the actual type, cast to it and invoke the method but that's a very bad design and I wouldn't recommend it. The consumer shouldn't know anything about the actual type. You will need to rethink your design.

楠木可依 2024-09-25 23:18:29

如果您想坚持当前的架构,您可以引入一个新的接口声明

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 操作和条件执行方法。如果您想坚持某些经典的设计模式,可以使用装饰模式或策略模式来应对这种行为的可变性。它们可以与工厂模式顺利结合。

If you want to stick to the current architecture you can introduce a new interface declaration

interface ICalculationRules  
{  
    string Calculate();  
}

Now let modify Client1BusinessRules by adding the interface declaration:

class Client1BusinessRules: IBusinessRules, ICalculationRules
{
     // everything remains the same  
}

Modify your calling code like this:

var objBase = objfactory.GetObject(1);  
Console.WriteLine(objBase.Calculate());    
var calcBase = obj as ICalculationRules;     
if (calcBase != null) calculable.Calculate();     

Maintenance implication: Every time you introduce a new interface, you have to touch all your calling code. Since you posted that this code is placed in the UI code, this can get quite a mess.

Each interface you are introducing just means added behaviour to a class. If you have a large range of different behaviours, then the solution above my not feel right, because there is always the need to use the as operation and conditional execution a method. If you want to stick to some classic design pattern this variability of behaviour can be countered with the Decorator Pattern or the Strategy Pattern. They can be smoothly combined with the Factory Pattern.

凉薄对峙 2024-09-25 23:18:29

在这种情况下可以采用多种方法,这取决于您愿意为获得价值而付出的成本。

例如,您可以进行简单的铸造。您将从工厂获取算法对象,将其转换为正确的(特定)算法对象,然后调用“计算”​​函数。

另一种选择(一种更通用的选择,也需要更多代码)是在基类中提供查询机制,该机制将提供有关对象中可用功能的信息。这在某种程度上类似于查询 COM 中的接口。

您需要问自己的重要问题是:
1. 您需要实现特定功能多少次?
2. 有没有办法通过添加来自基类的多态性来解决问题?
3. 派生对象的用户是否知道他们正在使用特定对象,还是希望他们不知道实际类型?

一般来说,我个人在这种情况下所做的就是从最简单的解决方案开始(在这种情况下,特定的转换和调用函数),然后当我有更多有关该领域的数据时返回并重构。如果您对“臭代码”很敏感,那么您会发现有太多混乱,并且会将其重构为更好的解决方案。

There are many approaches that can be employed in this case, and it depends on the cost you're willing to put in order to get the value.

For example, you can go with simple casting. You'll get the algorithm object from the factory, cast it to the proper (specific) algorithm object, and then call the "Calculate" function.

Another option - a much more generic one, that would also require much more code - would be to supply a querying mechanism within the base class, that will supply information about the available functionality within the object. This is somewhat comparable to querying for interfaces in COM.

The important questions you need to ask yourself is:
1. How many times will you need to implement specific functionality?
2. Is there a way you can solve the problem with added polymorphism stemming from the base class?
3. Will users of the derived objects know that they are using the specific object, or do you want them to be ignorant of the actual type?

In general what I personally do in such cases is start with the simplest solution (in this case, specific casting and calling the function), and go back and refactor as I go, when I have some more data about the domain. If you're sensitive to "smelly code", you'll get to a point where you see there's too much clutter and you'll refactor it into a better solution.

宫墨修音 2024-09-25 23:18:29

我会像这样修改它

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

扩展接口的一个大问题是,它根本没有给调用者任何提示,表明您可能支持该接口接口也是如此。

I would modify it like this

interface IBusinessRules
{
    string Perform();
    bool CanCalculate { get; }
    string Calculate();
}

and add an abstract base class (optional but recommended for further extensibility)

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
}

So the call site now looks neat:

objBase = objfactory.GetObject(1);
if (objBase.CanCalculate) {
    Console.WriteLine(objBase.Calculate());
}

One big problem of extending the interface is, it gives the caller no hint at all that you might support that interface as well.

年华零落成诗 2024-09-25 23:18:29

这是一个域建模问题,与问题域中 BusinessRule 和 IBase 的含义相关。

什么是IBase?听起来应该叫IBusinessRule。在这种情况下,“计算”在“业务规则”的上下文中意味着什么。如果它在您的域中具有通用含义,那么 IBusinessRule 应该像其他类一样实现它,即使只是作为空方法。

如果它在您的域中没有通用含义,那么您的类应该实现另一个具有Calculate 的接口ICalculableIAlgorithm?),您可以将其称为:

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

This is a domain modelling issue and relates to what you mean by BusinessRule and IBase in your problem domain.

What is IBase? Sounds like it should be called IBusinessRule. In which case, what does Calculate mean in the context of a "business rule". If it has a generic meaning in your domain then IBusinessRule should implement it, as should the other classes, even if only as an empty method.

If it doesn't have generic meaning in your domain then your class should implement another interface ICalculable (IAlgorithm?) that has Calculate, which you call as:

ICalculable calculable = obj as ICalculable;
if ( calculable != null ) calculable.Calculate();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文