Home » Java » java – Suggest design pattern-Exceptionshub

java – Suggest design pattern-Exceptionshub

Posted by: admin February 25, 2020 Leave a comment

Questions:

I have the following logic to be implemented:
There are two data sources, 1 and 2

Common methods to be executed for both data sources: functionOne, functionTwo, functionThree, functionFour

functionFive, functionSix, functionSeven are just run for data source 2

class Demo {

functionOne();
functionTwo();

if(dataSource.equals("1")){

     // Perform relevant logic specific to this dataSource
     functionThree();
     functionFour();

     return;
}

//If data source is not "1"
functionFive();
functionSix();
functionSeven();

functionThree();
functionFour();

return;

}

I am thinking of putting the logic for each data source in separate classes (say DemoDataSourceOne and DemoDataSourceTwo).
And have the common methods in a helper class (in the same package), then call the relevant methods using “helper.functionThree” for example.

Is this a good design or should I go for another design pattern in this case.

How to&Answers:

Move the common functionality used by both classes (function1-4) to an abstract base class and let your datasources extend it and implement the specifics (DS1 already has everything, while DS2 needs to implement function 5-7):

pubic abstract class BaseDataSource {
  public abstract void doSomething();

  protected void functionOne() {
    ...
  }
  protected void functionTwo() {
    ...
  }
  protected void functionThree() {
    ...
  }
  protected void functionFour() {
    ...
  }
}

public class DataSourceOne extends BaseDataSource {
  public void doSomething() {
    // we only need common functionality from the base class
    functionOne();
    functionTwo();

    functionThree();
    functionFour();

    return;
  }
}

public class DataSourceTwo extends BaseDataSource {
  public void doSomething() {
    functionOne();
    functionTwo();

    functionFive();
    functionSix();
    functionSeven();

    functionThree();
    functionFour();

    return;
  }
  // we need to implement the specific methods for Datasource 2
  protected void functionFive() {
    ...
  }
  protected void functionSix() {
    ...
  }
  protected void functionSeven() {
    ...
  }
}

Assuming, that your methods (function1-7) need to access data (variables) from the DataSources, it is safer to encapsulate the data and methods in a class hierarchy instead passing the data to helper / utility class.
Another aspect is the level of abstraction of the methods. If they are doing something that is closely connected with the datasources, e.g. opening connections the code is easier to understand (YMMV) when located with the classes. If it is some helper functionality that is only vaguely connected with the purpose of the class (e.g. String manipulation or logging), you’re probably better off moving this to a helper class.
Additionally, you can stronger enforce the common behaviour of the datasource, e.g. public abstract void doSomething() can be declared in the base class or an interface and each (future) datasource must implement it. And you can use template methods to further specify what each class must do, e. g. let’s say you want your “doSomething” method always to perform the following steps:

  1. open connection
  2. perform something with the connection
  3. close the connection

Assuming, #1 and #3 can be done in the base class, you could enforce this behaviour for the subclasses by implementing #1 and #3 in the base class and declaring #2 as abstract in the base class:

pubic abstract class BaseDataSource {
  public void doSomething() {
    openConnection();
    performQuery();
    closeConnection();
  }

  protected abstract void performQuery();

  protected void openConnection() {
    // common functionality for opening connection
  }

  protected void closeConnection() {
    // common functionality for closing connection
  }
}

public class DataSourceOne extends BaseDataSource {
  // method from base class must be implemented
  public void performQuery() {
    // specific query logic for base class
  }
}

With a helper class, you would repeat parts of the template for each datasource, e.g. the calls for opening and closing the connection when implementing doSomething for the next datasource making it harder to understand the commonanilites and differences between each class.

Answer:

This looks reasonable! But if you end up expanding this architecture to feature a larger number of DataSources; you may want to look into replacing what is basically your if-then statement chain (linear search) into a binary search format; so for example if your datasource was #360, it could go something like if DataSource<=500; if DataSource<=250 (false); if DataSource<=375 (true); if DataSource<=322 (false) etc. etc. until it finds the corresponding action for your DataSource. Not sure if this is relevant, but I thought I would throw that out there in case you do plan to use a lot of sources.