On its own, this is just an application of polymorphism, but you could also look at this as an incomplete Strategy pattern, with a couple of extras thrown in:
// 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();
}
}
A factory is just some function (or an object) that can create other objects; it's basically a more involved alternative to constructors (it's a "glorified constructor").
The Abstract Factory and Factory Method patterns are specialized kinds of factories, designed to solve more specialized kinds of creation-related problems. People will sometimes call a simple factory that is a function a factory function or a factory method, but that is different.
A Service Locator is a global (or a fairly global) object that you can ask for dependencies; it is generally considered an antipattern (as opposed to explicit Dependency Injection), primarily because of its global nature (you can call it from (more or less) anywhere), and because of the fact that it makes dependencies implicit (dependencies aren't reflected in the constructor or in the interface).
What's missing to your Almost-Strategy is an explicit Context object:
// 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();
Now, the whole idea of the Strategy pattern is that you can create these preconfigured Context instances and pass them around as objects. And potentially sometimes change the strategy they use dynamically (or not, you can design it either way).
So, something like:
// 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
If your client and/or context is very simple, or even if it isn't, but you haven't recognized as its own separate thing, and haven't gone through the refactor step to extract it out, and make it more explicit and better defined in code, you're not going to have an obvious Context object. And in fact, as the development progresses, you might, by inertia, repeat roughly the same code in several places, before you realize that these could be DRY-ed out by having instead several Context instances preconfigured with different strategies.