简体   繁体   中英

How to implement a factory pattern in a restrictive context?

I have a class, let's say A , that extends B . I cannot change neither the name of the class, nor what extends.

However, there is a method in A , let's say doSomething (which I cannot rename).

According to a flag, sent in the constructor of A I can do something or something else.

How do you suggest to handle the fork in doSomething according to the flag, given all these restrictions?

Thanks

Without further information:

public Foo doSomething() {
   if( flag ) {
       return super.doSomething();
   } else {
       return doSomethingElse();
   }
}

You could use the strategy pattern but it would add dozens of lines of code with little benefit other than the feeling you applied a design pattern.

With the necessary indirection in method calls, if might even be slower.

You can choose one of 2 options in my opinion:

  • Use the flag and for doSomething into 2 inner methods according to the flag. For example:

     public class A extends B { private boolean forkFlag; public A (boolean forkFlag) { this.forkFlag = forkFlag; } public void doSomething() { if (forkFlag) { doSomething1(); } else { doSomething2(); } } private void doSomething1() { ... } private void doSomething2() { ... } } 
  • Create a strategy implementation:

     public class A extends B { private boolean forkFlag; private Runnable doSomethingImpl; public A (boolean forkFlag) { if(forkFlag) { doSomethingImpl = new DoSomethingImpl1(); } else { doSomethingImpl = new DoSomethingImpl2(); } } public void doSomething() { doSomethingImpl.run(); } } public class DoSomethingImpl1 implements Runnable { public void run() { ... } } public class DoSomethingImpl2 implements Runnable { public void run() { ... } } 

Deciding between those 2 depends on your needs. If this fork is something minor, just a use case in a regular flow, I'd go with the first option. If there's a chance that you might need to have a third flow I'd go with the strategy pattern and enjoy the decoupling it provides.

With strategy you'll be able to inject the implementation you want from outside the class and be totally unaware of the implementation of doSomething just by changing the constructor:

public A (Runnable doSomething) {
   this.doSomething = doSomething;
}

The injection pattern is probably the most elegant and will create a complete decoupling of your code from the implementation. Also, you might change the implements Runnable into a more specific interface of your own public interface DoSomething to make it more robust.

you have to use Strategy pattern here

public A(boolean flag){
    if(flag == true){
        this.service = new DoSomethingStrategy();
    }else{
        this.service = new DoSomethingElseStrategy();
    }
}

if your code grows, logically, better use a Factory on constructor:

public A(boolean flag){
    this.service = DoSomethingFactory.getService(flag);
}

and copy the code inside the DoSomethingFactory ;

and finally on your doSomething method

public void doSomething(){
    this.service.doSomething();
}

and your behaviour for doSomething is encapsulated into a strategy structure.

Why can't you create another class C that also extends B and use it instead of A as necessary? It's usually better to avoid conditionals and hard-coding the construction of strategies inside a class, if you can.

You don't need to touch the base class, just extend it with another implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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