abstract class BaseService {
public void doSomething();
}
class AService extends BaseService {
public void doSomething(){
// Do something...
}
}
class BService extends BaseService {
public void doSomething(){
// Do something...
}
}
class ServiceResolver {
pubic static BaseService resolveService(String type) {
if(type == "A") return new AService();
if (type == "B") return new BService();
}
}
Usage:
BaseService resolvedService = ServiceResolver.resolveService(type);
resolvedService.doSomething();我们把上面的模式叫做什么?这是否与战略模式相同?我觉得这是不同的,因为在策略模式中,客户端选择算法类型(https://refactoring.guru/design-patterns/strategy)并将其传递给上下文类执行,并在运行时更改对象的行为(上下文类对象),但在我的上面示例中,我们没有做任何这样的事情。
此外,在扩展上述代码时:
class ServiceResolver {
@Autowired
AService aService;
@Autowired
BService bService;
pubic static BaseService resolveService(String type) {
if(type == "A") return aService;
if (type == "B") return bService;
}
}从总体上看,它和第一个看起来是一样的。
发布于 2021-10-21 18:30:42
我最初称这为工厂方法模式,但正如菲利普所指出的,这是不正确的。它实际上只是一个充当对象工厂的方法。我明白为什么您可能认为它与策略模式相关,但是在策略中,底层实现对象的更改是在策略对象中完成的。在这种情况下,意图是不同的,因为您正在创建这些对象,并将它们交给系统的其他部分来管理。
您在这里所做的事情是一种有用而简单的方法,可以消除对具体类及其构造函数的显式依赖。如果它满足了您的需要,我认为没有理由通过实现更正式的Factory方法模式来使事情变得过于复杂。
发布于 2021-10-21 20:26:26
就其本身而言,这只是一个多态应用程序,但您也可以将其看作是一个不完整的策略模式,添加了几个附加元素:
// abstract strategy type
abstract class BaseService {
public void doSomething();
}
// concrete strategy A
class AService extends BaseService {
public void doSomething(){
...
}
}
// concrete strategy B
class BService extends BaseService {
public void doSomething(){
...
}
}
// A factory (not an Abstract Factory, not a Factory Method)
// acting as a Service Locator ("service resolver" basically means the same thing)
class ServiceResolver {
pubic static BaseService resolveService(String type) {
if(type == "A") return new AService();
if (type == "B") return new BService();
}
}工厂只是一些可以创建其他对象的函数(或对象);它基本上是构造函数的一个更复杂的替代(它是一个“美化的构造函数”)。
抽象工厂和工厂法模式是专门的工厂类型,旨在解决更多与创建相关的特殊类型的问题。人们有时会称一个简单的工厂为一个函数,一个工厂函数或一个工厂方法,但这是不同的。
服务定位器是一个全局(或相当全局的)对象,您可以请求依赖项;它通常被认为是反模式(而不是显式依赖注入),主要是因为它的全局性质(您可以在任何地方调用它(或多或少),也因为它使依赖关系隐式(依赖关系没有反映在构造函数或接口中)。
“几乎-策略”中缺少的是一个显式的上下文对象:
// This is the code that selects the strategy.
// So, it could be seen as the client (or a part of it).
// It doesn't matter that it delegates the job to the service locator
BaseService resolvedService = ServiceResolver.resolveService(type);
// This is the "guts" (what would be the internal details) of your nonexistent Context
resolvedService.doSomething();现在,战略模式的全部思想是,您可以创建这些预先配置的上下文实例,并将它们作为对象传递。而且有时可能会动态地改变他们使用的策略(或者不是,您可以任意设计)。
所以,就像:
// The Context
class Doer {
pubic void doTheThing() {
/* some higher-level logic/algorithm */
// step 1
// step 2
// ...
// step i - varies - delegate to the strategy:
this.resolvedService.doSomething();
// ...
// step N
}
// maybe some other methods...
}
// -----------------------------
// In the client:
Doer doer = new Doer(ServiceResolver.resolveService(type));
// call it or send it on its way如果您的客户端和/或上下文非常简单,或者即使不是,但您还没有认识到它是它自己的单独的东西,并且没有经历重构步骤来提取它,并使它在代码中更显化和更好地定义,那么您将不会有一个明显的上下文对象。事实上,随着开发的进展,您可能会惯性地在几个地方重复大致相同的代码,然后您才会意识到,通过使用不同的策略预先配置几个上下文实例,这些代码可能会变得干涸。
发布于 2021-10-22 07:39:09
在您的第一个代码示例中,您有一个工厂,但它是一个有问题的工厂。它是一个静态方法,所以任何使用这个工厂的代码都会紧密耦合到这个实现中。其次,该方法本身与具体实现紧密耦合:AService和BService。所有这些紧密耦合使得测试这些代码非常困难。静态工厂是那些与反模式有关的工厂之一。如果它提供的对象是确定性的和无副作用的,那么它们是可以的,但是服务不太可能满足这个要求,因此这种方法在这里可以被看作是一个糟糕的方法。
第二个代码示例,您似乎正在注入aService和bService,这是很好的。你的工厂已经改进了。但是,您已经将这两项耦合到具体类型,AService和BService,这很糟糕,因为依赖注入增加了复杂性,除了消除第一个示例中的"new胶水“耦合问题之外,没有提供更多的好处。你已经减少了你的耦合,但仍然有一些。不幸的是,这是货物偷盗的一个例子。这些类型需要替换为抽象类或接口,这取决于您的语言支持。
但事情会变得很奇怪。resolveService仍然是静态的,但它访问实例成员aService和bService。我看不出这是怎么编出来的。那是个错误吗?
在您对JimmyJames的评论中,您将介绍代码AService.getInstance()。这是单例模式的一个例子。它只是一个被美化的全局变量,也是一个绝对的反模式。单例应该仅通过DI注入来处理。
https://softwareengineering.stackexchange.com/questions/432908
复制相似问题