所以在我的应用程序中,我有几个不同的客户被“服务”。每个客户都有自己的各种类的实现,这些类都基于接口。
随着最新客户的加入,我注意到会有很多来自其他客户的代码重复,但另一位客户与其他客户无关。
我已经为其他几个客户提供了默认实现,并根据需要推出了新的实现。
我的问题是我如何重构这个仍然保持代码清洁?如果我是这个代码库的新手,我希望每个客户使用这些类的默认或他们自己的实现......但这是很多重复。
答案 0 :(得分:5)
考虑使用abstract
基类与abstract
或virtual
成员。抽象成员本质上等同于接口成员(它们没有内置行为,它们只保证方法存在),而virtual
成员有一个默认实现,可以被派生类覆盖。
你的问题实在太模糊了,无法全面回答,但这里是你如何利用继承。
如果希望所有类使用成员的相同实现,那么该成员可以在基类中实现。
如果您希望每个类拥有自己的成员实现,那么您可以使用带有abstract
成员的基类或接口
如果您希望某些类使用相同的实现,而其他类使用不同的实现,则在基类中实现默认行为并根据需要覆盖它。 / p>
我的主要观点是OOP在基础/抽象/具体类中存在多少或多少功能。没有银弹答案,有时你的基础类将是骷髅,有时他们会完全充实;这一切都取决于手头的具体问题。
答案 1 :(得分:2)
是否有某种方法可以创建基类,然后为每个客户提供特定的实现,然后使用某种类型的依赖注入,根据需要加载类或功能。你想要真正拥有DRY系统,以避免头痛和拼写错误或其他类似的人为错误。
答案 2 :(得分:1)
您可以使用继承(将通用逻辑放入基类)或聚合(在其他类中传播该逻辑并从客户使用它们)。
答案 3 :(得分:1)
如果不更好地理解代码,知道建议什么有点困难......但是在类似情况下对我有用的一些事情包括:
STW建议我应该对“战略”的含义做一些澄清,以及它与正常继承的区别。我认为继承是你非常熟悉的东西 - 基类中的某些东西(通常是一个方法 - abstract
或virtual
)被派生类中的替代实现替换。
策略(至少我通常使用它的方式)通常由完全不同的类实现。通常,该类将包含的是单个可替换操作的实现。例如,如果“操作”是要执行某些验证,那么您可能会NullValidationStrategy
执行任何操作,而ParanoidValidationStrategy
可确保每个McGuffin都具有正确的高度,宽度和特定的蓝色阴影。我通常在自己的类中实现每个策略的原因是因为我尝试遵循Single Responsibility Principle,这可以使以后更容易重用代码。
如上所述,我通常使用依赖注入(DI)框架通过类构造函数“注入”适当的策略,但是可以通过其他机制获得类似的结果 - 例如拥有SetSomeOperationStrategy(ISomeOperation StrategyToUse)
方法或拥有策略参考的属性。如果您不使用DI,并且对于给定的客户类型,策略将始终相同,则可以在构造类时始终设置正确的选择。如果策略对于给定客户类型的每个实例都不相同,那么您可能需要某种类型的客户factory(通常factory method就足够了。)
答案 4 :(得分:1)
我推荐访客模式:
http://en.m.wikipedia.org/wiki/Visitor_pattern
以及调解员模式:
http://en.m.wikipedia.org/wiki/Mediator_pattern
原因在于,根据您所说的内容,您可能会从类中解除业务逻辑,或者至少更松散耦合,从而获益。
答案 5 :(得分:0)
我会选择spinon的答案(至少得到我的投票),但是要做空,所以让我详细说明:
使用您的接口进行默认实现,然后使用依赖注入。大多数工具允许您定义范围或某些标准以解决问题。
我假设您在程序的某个早期阶段确实了解客户端。因此,对于ninject,您可能只想为每个客户端定义一个“模块”并将其加载到内核中,具体取决于客户端。
所以我创建了一个“no customization”模块,并为每个使用'Bound.To()`的特殊情况创建一个“ClientX”模块。 你最终得到了
代码的其余部分不应该介意并通过注入获取依赖项(构造函数,属性,最简单的方法。构造函数可能是最好的方法)并且根本没有特殊处理。
你甚至可以在Ninject conditional binding中使用link text来解决绑定问题而根本没有不同的模块(尽管,根据客户端的数量,这可能会变得混乱,最好分开)
答案 6 :(得分:0)
正如@the_joric建议的那样,我建议聚合继承,但你的描述听起来好像你的应用程序已经合理地考虑了因素 - 没有很多小类等待从你的提取现有的课程。假设情况就是如此,对于任何给定的界面,如果你已经为已经编写并准备好的新客户提供了一个完美的类,我会说继续使用它。如果您担心这一点,出于某种原因,那么就选择完美的课程,将其抽象化,并为现有客户和新客户创建空子类 - 如果它不是完美契合,那就是我的方式去。