简体   繁体   English

工厂模式很多参数需要提示

[英]Factory Pattern many parameters need tips

I'm designing a small "Rule Engine" solution. 我正在设计一个小的“规则引擎”解决方案。 Basic idea of module is that it checks whether received user interactions satisfy some rules and if yes then gives them bonus points. 模块的基本思想是检查接收到的用户交互是否满足某些规则,如果是,则给予奖励积分。 In short, there is a collection of List<IRule> interfaces, when user interacts with system, let's say buys stuff, I iterate to all IRule -s and check if bool Execute(ITransactionContext context) returns true. 简而言之,有一个List<IRule>接口的集合,当用户与系统交互时,假设买东西,我迭代到所有IRule -s并检查bool Execute(ITransactionContext context)返回true。 Here's IRule interface 这是IRule界面

public interface IRule
{
    bool Execute(IContext context);
}

And the problem is that concrete Rule : IRule classes differ from each other, have different parameters and meanings. 问题在于具体Rule : IRule类彼此不同,具有不同的参数和含义。 Eg 例如

  • AmountRule has Min, Max properties AmountRule具有Min, Max属性
  • DatePeriodRule has From and To parameters DatePeriodRule具有FromTo参数
  • EqualsRule has CheckProperty and ExpectedValue parameters and so on... These are very basic and simple rules, there may be exist more complicated rule. EqualsRuleCheckPropertyExpectedValue参数......这些是非常基本和简单的规则,可能存在更复杂的规则。

     public class AmountRule : IRule { private decimal _min; private decimal _max; public bool Execute(IContext context) { return context.Amount >= _min && context.Amount <= _max; } } public class DatePeriodRule : IRule { private DateTime _from; private DateTime _to; public bool Execute(IContext context) { return context.ProcessDate >= _from && context.ProcessDate <= _to; } } 

So creating rules is not an easy task and I decided to use the Factory Pattern (or any pattern related to it, don't mind if it's an Abstract Factory , Factory Method or Builder ) and have an interface IRuleFactory which is responsible for creating any kind of IRule implementation class. 所以创建规则并不是一件容易的事,我决定使用工厂模式 (或任何与之相关的模式,不介意它是Abstract FactoryFactory Method还是Builder )并且有一个接口IRuleFactory ,它负责创建任何规则。一种IRule实现类。

public interface IRuleFactory
{
    IRule Create(RuleType type);
}

I face real problem here because of the parameter variety for concrete implementations of IRule . 我在这里遇到了真正的问题,因为IRule具体实现具有参数多样性。 Eg If I want to create AmountRule then my RuleFactory needs MinAmount, MaxAmount params, If DatePeriodRule it needs From, To params and so on... 例如,如果我想创建AmountRule那么我的RuleFactory需要MinAmount, MaxAmount参数,如果DatePeriodRule需要From, To params等等......

I'm looking for some good approaches to solve this problem. 我正在寻找一些解决这个问题的好方法。 Is Factory just an extra headache here? Factory只是一个额外的头痛吗?

It's ok for your Factory to create specific types that implement an interface but have constructors with different parameters. 您的Factory可以创建实现接口但具有不同参数的构造函数的特定类型。 That's exactly the type of abstraction it's meant for. 这正是它意味着的抽象类型。 So your Create method could look something like the following: 因此,您的Create方法可能如下所示:

IRule Create(RuleType type){
    if(type == RuleType.ValidAmount){
        return new ValidAmountRule(10, 20);
    }
    else{
        return new OtherKindOfRule("some other param");
    }
}

Of course it's assumed here that your Factory knows what the parameters for the constructors should be. 当然,这里假设您的工厂知道构造函数的参数应该是什么。 If this is only known by the client of the Create method, then I would say the indirection isn't necessary and the client should construct the rule itself. 如果这只是Create方法的客户端所知,那么我会说间接不是必需的,客户端应该自己构造规则。 The RuleType parameter is a bit suspicious in that the caller obviously has to know something about the IRule it wants. RuleType参数有点可疑,因为调用者显然必须知道它想要的IRule If there is a one to one mapping between RuleType and a concrete type to be constructed then this is certainly needless complexity unless the caller just doesn't have the information it needs to construct the rule directly. 如果RuleType和要构造的具体类型之间存在一对一的映射,那么这肯定是不必要的复杂性,除非调用者只是没有直接构造规则所需的信息。

In general, the point of a rules engine is to reduce complexity by removing a bunch of complicated if/else statements and encapsulating rules so they can be managed in isolation and possibly configured outside a code deployment. 一般而言,规则引擎的目的是通过删除一堆复杂的if / else语句并封装规则来降低复杂性,以便可以单独管理它们并可能在代码部署之外进行配置。 Your concrete rules have to get the information they need to apply their logic from some combination of the constructor of the object and the caller of the object. 您的具体规则必须获取从对象的构造函数和对象的调用者的某种组合应用其逻辑所需的信息。 What can't be known in the object constructor has to be passed to your Execute method. 必须将对象构造函数中无法知道的内容传递给Execute方法。 That means that the parameter in your IRule interface should be a high-level object that contains a lot of information that some of your rules may not even need. 这意味着IRule接口中的参数应该是一个高级对象,其中包含许多规则甚至可能不需要的信息。

I have actually implemented a RulesEngine called Ariadne so I speak from experience here. 我实际上实现了一个名为Ariadne的RulesEngine,所以我从这里的经验谈起。 Your dilemma comes from the fact that you have varying operand types and they have to line up. 你的困境来自于你有不同的操作数类型,他们必须排队。 After all, you can't ask 毕竟,你不能问

is 'foo' > 10 是'foo'> 10

that expression is invalid because foo is a string and 10 is a number. 该表达式无效,因为foo是一个字符串,10是一个数字。 Similarly, you can't ask if 同样,你不能问是否

Weight > 15lbs 重量> 15磅

Because computers don't know what 'Weight' is or what '15 lbs' is. 因为计算机不知道“重量”是什么或者“15磅”是什么。

You have to manage this with a variety of patterns and well thought design. 你必须通过各种模式和精心设计来管理它。

The design architecture of Ariadne (and you are welcome to try to take some liberties) was this: You have Ariadne的设计架构(欢迎你尝试采取一些自由)是这样的:你有

  • Operations (Predicates, Equations, etc.) 操作(谓词,方程等)
  • Operators ( plus, minus, divide, etc). 运算符(加,减,除等)。 (Ariadne, for simplicity sake does binary ops) (Ariadne,为简单起见,做二元操作)
  • OperandOwners (These are objects that extract a numeric value from 'Weight' so you can do things like 'Weight > 10'. OperandOwners(这些是从'Weight'中提取数值的对象,因此您可以执行'Weight> 10'之类的操作。
  • All implementations of the above are entirely stateless. 上述所有实现都是完全无状态的。 Gathering whatever information they needed from the call context. 从呼叫上下文中收集他们需要的任何信息。

Your first problem is to keep all the Operations, Operators and OperandOwners in the same KnowledgeBase -- This is crucial for running more than 1 in your app. 您的第一个问题是将所有操作,操作员和操作员都保留在同一知识库中 - 这对于在您的应用中运行多个操作系统至关重要。 The way I did this was with a AbstractFactory pattern . 我这样做的方式是使用AbstractFactory模式

In this example you can see: 此示例中,您可以看到:

KnowledgeBase kb = KnowledgeBase.getInstance();

Is how I control these 3 pieces. 我是如何控制这3件作品的。 If you try to manage an operator/operand/operandowner they all go through this knowledgbase because you have to call it's functions 如果你试图管理一个operator / operand / operandowner,他们都会通过这个knowledgbase,因为你必须调用它的函数

You also need to be able to funnel the creation of rules into your methods . 您还需要能够将规则的创建汇集到您的方法中

public Predicate getPredicate(OperandOwner lho, String op, OperandOwner rho) throws AriadneException {
    return operationFact.getPredicate(lho, op, rho);
}

This is a registration process that allows for the reuse of common objects through use of the Flyweight pattern and in addition, it is a Factory method for producing predicates. 这是一个注册过程,允许通过使用Flyweight模式重用公共对象,此外,它是一个用于生成谓词的Factory方法

All this is well and good, but really, you want to be able to combine rules arbitrarily. 这一切都很好,但实际上,你希望能够任意组合规则。 To do this you need to continue to combine them but expose them as a single rule. 要执行此操作,您需要继续组合它们,但将它们作为单个规则公开。 This many as one pattern is the composite pattern. 这一多个模式是复合模式。 Consider: 考虑:

  • is today tuesday ? 是星期二今天?
  • is it raining ? 在下雨吗 ?
  • is my weight > 10lbs 是我的体重> 10磅

You have 3 separate predicates that can be combined. 您有3个单独的谓词可以组合。 And in any combination of 'and' or 'or' you still have a predicate. 在'和'或'或'的任意组合中,你仍然有一个谓词。 You must be able to represent many combined predicates as one. 您必须能够将许多组合谓词表示为一个。

For an example of how this works look here 有关其工作原理的示例,请参见此处

Bottom line: A robust implementation will be: 结论:强大的实施将是:

  1. Memory efficient. 内存效率高。 Rules are bound to be endless 规则必然是无止境的
  2. Stateless. 无状态。 Side-effects can bring the whole thing down 副作用可以降低整体效果
  3. Open for extension (Ariadne allows/encourages you to roll your own operators/operand owners) 开放进行扩展(Ariadne允许/鼓励您推广自己的运营商/操作数所有者)
  4. closed for modification 关闭修改
  5. Next to impossible to get rule creation wrong. 接下来不可能让规则创建错误。

To this end you have: 为此你有:

  • Flyweight 飞锤
  • Composite 综合
  • Abstract Factory 抽象工厂
  • Factory Method 工厂方法

Good luck 祝好运

I would apply prototype pattern to register rules. 我会应用原型模式来注册规则。 If all rules you anticipate to have are stateless you even can do without cloning. 如果你预期的所有规则都是无状态的,你甚至可以不进行克隆。

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

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