Make application layer loosely coupled

I have a Java Spring-boot application that has layers ( packages ) in it:

  • Controller (controller class)
  • Service (business logic)
  • Domain (database level)

Inside My Domain I have two database classes

  • Mysqldbmanager
  • MongoDBManager

I have many classes in my service package , which uses both the MysqlDBManager and MongoDBManager .

If I use instances of MysqlDBManager' and MongoDBManager` in my service class, the service will be closely related to the domain level.

To solve this problem, I created a class called **DBManager** in my domain package, which behaves like a proxy class that calls MysqlDBManager' and MongoDBManager` based on internal usage.

Now the service layer, not the call MysqlDBManager' and MongoDBManager directly they call DBManager , which internally calls MysqlDBManager' and MongoDBManager .

Therefore, now my class of service is not closely related to the domain layer.

Below are my classes, similar to my use case.

MongoDBManager class:

  Class MongoDBManager { public saveUserDocs(String docs) { //..... } } 

MysqlDBManager Class:

 Class MysqlDBManager { public saveUserData(List<String> rows) { //..... } } 

DBManager class:

  Class DBManager { @Autowired private MysqlDBManager mysqlDBManager; @Autowired private MongoDBManager mongoDBManager; public saveUserData(List<String> rows) { mysqlDBManager.saveUserData(rows); } public saveUserDocs(String docs) { mongoDBManager.saveUserDocs(docs); } } 

Class of service:

 class Service { @Autowired private DBManager dBManager; //....... code here dBManager.saveUserData(rows); dBManager.saveUserDocs(docs); } 

My question is :

Is this (as explained above) a good way to make application layers loosely coupled, or are there better ways to do this?

+5
source share
2 answers

IMHO there is a better way. Interfaces will help you to freely pair, here is an example:

 interface DocsDBManager { void saveUserDocs(String docs); } interface UserDBManager { void saveUserData(List<String> rows); } interface DBManager extends DocsDBManager, UserDBManager { } 

And you must implement them:

 class MongoDBManager implements DocsDBManager { public void saveUserDocs(String docs) { //..... } } class MysqlDBManager implements UserDBManager { public void saveUserData(List<String> rows) { //..... } } 

and

 class DBManagerBase implements DBManager { @Autowired private DocsDBManager docsDBManager; @Autowired private UserDBManager userDBManager; public void saveUserData(List<String> rows) { userDBManager.saveUserData(rows); } public void saveUserDocs(String docs) { docsDBManager.saveUserDocs(docs); } } 

And finally:

 class Service { @Autowired private DBManager dBManager; //....... code here dBManager.saveUserData(rows); dBManager.saveUserDocs(docs); } 
+4
source

You fit well, it looks like some kind of facade design pattern, but I would recommend a more traditional way.

You already have spring as an IoC container, so all you have to do is extract the interfaces from your *DBManager classes and tell spring about your implementations. Then you can implement the actual implementation using the interface, which, in turn, can be in a completely different package. Therefore, the connection will cease to exist.

Here is an example.

DataStorage Contract:

 package root; import java.util.List; public interface UserDataStorage { void saveUserData(List<String> rows); } 

DocumentStorage Contract:

 package root; public interface UserDocumentStorage { void saveUserDocs(String docs); } 

DataStorage implementation:

 package root.domain; import org.springframework.stereotype.Service; import root.UserDataStorage; import java.util.List; @Service public class MysqlDBManager implements UserDataStorage { @Override public void saveUserData(List<String> rows) { System.out.println("Saving data...."); } } 

DocumentStorage implementation:

 package root.domain; import org.springframework.stereotype.Service; import root.UserDocumentStorage; @Service public class MongoDBManager implements UserDocumentStorage { @Override public void saveUserDocs(String docs) { System.out.println("Saving docs...."); } } 

Then your service classes might look like this (note: domain link is missing:

 package root.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import root.UserDataStorage; import root.UserDocumentStorage; import java.util.Collections; @Service public class MyService { private final UserDataStorage dataStorage; private final UserDocumentStorage documentStorage; @Autowired public MyService(UserDataStorage dataStorage, UserDocumentStorage documentStorage) { this.dataStorage = dataStorage; this.documentStorage = documentStorage; } public void callMe() { this.dataStorage.saveUserData(Collections.emptyList()); this.documentStorage.saveUserDocs("Document1"); } } 
+4
source

Source: https://habr.com/ru/post/1272485/


All Articles