如何提供插件模型,其中不同的插件采用不同的参数
我写的代码( MyService
)包括每个客户在处理过程中的特定点插入自己的计算器的能力。 这是为了允许自定义业务规则。 在计算完成时,我们知道各种各样的事情,其中一些可能与计算有关。 将为特定的输入参数集创建MyService
并运行一次。
我的计划是使用dependency injection在构造函数中为MyService
提供calculator
。 这允许不同的用户插入他们自己的calculator
。 calculator
将返回一个金额,表示此特定MyService
运行应付的附加费。 其他人将实现各种计算器,我需要能够更新我的代码而不会破坏他们的代码。 即。 保持向后兼容性。
我遇到的问题是各种计算器实现需要不同的参数。 在创建MyService
时,这些参数不能被构造函数注入到计算器中,因为不知道MyService
某些处理发生了。
计算器只会在MyService
的特定实例中调用一次。 因此,在一个极端,所有参数都可以在构造函数中传递,并且有一个方法没有返回答案的参数。 另一方面,所有参数都在方法调用中传递。
AlwaysZeroCalculator
可能只return 0
因此不需要参数。 PercentageCalculator
需要amount
才能应用百分比。 更复杂的需要amount
和customerNumber
。 我们可以假设calculator
可能需要的任何东西在运行时都是MyService
已知的(或者它本身可以注入到calculator
实现中,就像hibernate Session一样)。
我该如何实现呢?
以下是一些选项和问题:
- 使所有计算器实现一个包含所有参数作为方法参数的接口。 但是,如果添加额外的东西,那么他们都需要改变,这将不可避免地将其转变为第二种选择。
- 制作不同的接口(
ICalculator
,ICalculatorWithAmount
,ICalculatorWithAmountAndCustomerNumber
等)。MyService
需要查看它实现的calculator
接口,将其转换为该接口,然后调用相应的calculate(..)
方法。 - 引入一个参数对象,其中包含任何他们关心的任何内容。 这意味着即使是最简单的
calculator
取决于一切。 - 使
MyService
不同接口和不同版本期望其中一个接口。 - 注入
calculatorFactory
而不是calculator
。 工厂将采用所有可能的参数,并创建一个只有正确的计算器。 这似乎只是将问题转移到其他地方而没有解决它。 - 将一些可怕的hashmap传递给计算器并键入安全性,依赖性声明被诅咒
有没有更好的办法?
这是两个问题:
- 使用计算器
- 实例化计算器
第一个很容易 – 所有计算器都做同样的事情,可以有相同的界面。 后者是要解决的问题,因为它需要每个计算器实例的不同参数。
从您列出的是工厂最好的解决方案。 它并没有将问题转移到其他地方,它解决了这个问题。 每个工厂都知道它的计算器并知道它需要什么参数。 所以工厂依靠计算器。 使用工厂创建计算器只会创建计算器而不是其参数或计算器本身,它可以是所有工厂实现的工厂接口的一部分。
为工厂提供参数可以通过使用您选择的任何方式进行物业注入来解决 – spring绝对不错。
该应用程序反过来只知道如何使用计算器,因此取决于通用计算器接口而不是任何特定的计算器实现。
假设您正在使用spring …也许bean标记的factory-bean和factory-method属性可能很有用。
伪代码……
我总是很难获得运行时依赖项以优雅的方式使用dependency injection。
但是,我会针对您的“制作不同的界面”计划进行修改。
每个计算器都会定义它自己的界面,例如IAlwaysZeroCalculatorParameters
, IPercentageCalculatorParameters
等。
然后,您的MyService
类可以实现所有这些接口,然后将其自身传递给每个计算器。
实现这一目标的框架开销非常小,这意味着每个计算器都能简洁地表达它所需要的内容。 在类似情况下,它对我很有效,尽管在您的特定情况下(您无法控制插件),这意味着每次有人实现新计算器时都必须释放MyService
(以便它可以实现新接口) )。 如果需要,我可能会用一些Duck Typing来解决这个问题。
此计算器使用abstract
FunctionAdapter
按名称评估函数。 每个具体的子类都实现了一个带有可变数量参数的eval()
方法。