Back to feed
Renewal·서른의 생활코딩

Following Toby's Spring 3.1 in Spring Boot: Ch.1 - 1.3 Extending the DAO

NS
normalstory
cover image

Following Toby's Spring 3.1 in Spring Boot : Chapter 1 Objects and Dependencies - 1.3 Extending the DAO

Dev environment 

- OS : mac

- STS : 4.0.1

- MySQL : Server version: 8.0.13 Homebrew

- Framework : proceeding with a jar only, keeping dependencies as minimal as possible


Related links 

- Korean Spring User Group homepage     http://www.ksug.org/

- Korean Spring User Group Q&A     https://groups.google.com/forum/#!topic/ksug/13vB4tCFqrI

- 2017 Spring Camp                       https://www.youtube.com/playlist?list=PLdHtZnJh1KdZ6NDO9zc9hF4tONDLTSEUV



Chapter 1 Objects and Dependencies 

1.3 Extending the DAO 

Separation of concerns. You can think of it as gathering things with the same concern into a single object or closely related objects, and keeping things with different concerns as far apart as possible so they don't influence each other. 


1.3.0 Review so far 

1. We took the awful DAO and pulled its logic into independent methods  to separate them

2. We split it into a parent/child class pair.

1) Parent class — abstract class 

2) Child class — a subclass that inherits from the abstract class 

3. The development methodologies that embody this kind of process 

1) Design pattern

2) Template Method pattern

3) Factory Method pattern 


1.3.1 Separating the class — making SimpleConnectionMaker a standalone class

1. Instead of a subclass, create a new separate class to hold the DB connection info. 

2. Use this class inside UserDao's add() and get() methods by creating instances of it with the  new keyword.

To avoid creating the object every single time 

-> create it with 'new' in the constructor and declare it as a private field (instance variable). 

3. Result when run: success 

export_1.3.1 Separating the class:  

study_spring190220_1.zip
Download


   1) In the project list panel on the left -> right-click in empty space ->  import -> Existing Projects into Workspace -> select the downloaded file 

   2) If you already imported files from a previous post, please delete or rename the previous project before importing again.  

+ But (new issue!)  

The picture I wanted at first was 

Interface-introduced structure

but what actually came out is more like the highlighted block in the screenshot below

Even when we split the class this way, two problems still need to be solved to enable free extension, just as we saw with inheritance. 

First, the makeNewConnection() method is a problem. 

If company N or company D uses a different method name, the code inside UserDao's constructor — and inside add() and get()  — has to be changed every single time. 

Second, UserDao has to know concretely which class provides the DB connection. 

UserDao even defines an instance variable of the SimpleConnectionMaker type, so if company N or company D implements a class with a different name, UserDao itself has to be modified. 

   The root cause is that UserDao knows too much about the volatile piece — the class that pulls in the DB connection. 

It has to know which class will be used (what its name is) and what the name of the method that fetches the connection info is. In other words, UserDao ends up tied to a specific way of getting the DB connection. 





1.3.2 Introducing an interface

1. Structure <figure 1-4> p.75  The real structure is actually <figure 1-5>.

2. To keep the two classes from being tightly coupled, we create an abstract, loose link in between.

3. Abstraction is the act of pulling out the common nature of things and separating it off on its own. 

Java gives us the 'interface' for exactly this. An interface hides all the concrete information about the class that implements it. 

-> So that's why we've been connecting classes through an interface in between instead of directly!

In the end, where you used to have to pick a specific concrete class to create an object, now when you approach through the minimal passage abstracted by the interface, you don't need to know which class is being used to create the object. Once you go through an interface, it doesn't matter if the concrete implementation class changes.

4. Process 

1) Create the interface 

2) Create a dedicated class to hold the client's DB connection

3) Create the client's DB-connection class that implements the interface and write the DB connection code 

4) Declare an interface-typed object in UserDao and connect via the client's DB-connection class method 

5) Define the UserDao object in User.class's main() and adjust the PK value of the inserted data so the project can run

export_1.3.2 Introducing an interface :  

study_spring190220_2.zip
Download


   1) In the project list panel on the left -> right-click in empty space ->  
import -> Existing Projects into Workspace -> select the downloaded file 

   2) If you already imported files from a previous post, please delete or rename the previous project before importing again. 



+ But (new issue!)  

If you look at the current project structure as shown below 

A structure with unnecessary dependencies between classes

Even after applying the interface, UserDao's constructor still ends up with the concrete class name declared by company N or D. 

connectionMaker = new DConnectionMaker();

The code is short, but it means deciding which ConnectionMaker implementation class's object UserDao will use. In other words, it's a concern about the relationship between UserDao and the particular ConnectionMaker implementation it's going to use. 



1.3.3 Separating the relationship-setup responsibility — splitting client and service 


1. A relationship existing between classes means one class uses another directly, without any interface in between. So instead of a class-to-class relationship, we need to set up an object-to-object relationship.


2. A relationship between objects is formed at runtime, with one side holding a reference to another object.

connectionMaker = new DConnectionMaker();

= By putting the reference of the DConnectionMaker object into UserDao's connectionMaker field and using it, the two objects form a 'uses' relationship.

For a relationship to form between objects, the objects first have to exist — you can directly call a constructor, or use an object created externally.

Since objects can be passed around via method parameters and such, you can bring in an externally created one. To receive an externally created object, use a method parameter or a constructor parameter. 


3. You must be able to clearly distinguish between a class-to-class relationship and a dynamic object-to-object relationship. 

A class-to-class relationship is formed because another class's name appears in the code. 

But an object-to-object relationship is different. Even if the code knows nothing at all about a specific class, as long as it uses the interface that class implements it can take the object of that class via the interface type  and use it. This is precisely because object-oriented programs have the trait called polymorphism. 

So, to make a UserDao object use that other object, all you need is to set up a runtime use-relationship — also called a link or dependency — between the two class objects. 


4. Conclusion — define the client role  

1) Structural change

Actually, it was the client's responsibility that took the class structure in the earlier <figure 1-4> and turned it into the runtime object-relationship structure of <figure 1-6>.


2) Reflecting this back into the composition

Since the client is the one that needs to use UserDao, let's offload the concern UserDao's constructor has been carrying — 'creating the object I'm going to use and setting up my own relationship with it' — onto the client. To do that, move the main() that was in UserDao into a new UserDaoTest.class. 

And modify the constructor in UserDao so the client can pass in a pre-made ConnectionMaker object — add a single parameter. Starting from a structure like <figure 1-4>, we've finally arrived at a structure like <figure 1-7>. 

A composition with a client that takes on the relationship-setup responsibility


-> The upshot: we've created a client that handles the relationship setup.


3) Final code 

 export_1.3.3 Separating the relationship-setup responsibility: 

study_spring190220_3.zip
Download

   1) In the project list panel on the left -> right-click in empty space ->  import -> Existing Projects into Workspace -> select the downloaded file


   2) If you already imported files from a previous post, please delete or rename the previous project before importing again.





1.3.4 Principles and patterns

1. SOLID — object-oriented design principles

 Single Responsibility     SRP The Single Responsibility Principle

 Open/Closed     OCP Open Close Principle 

 Liskov Substitution     LSP The Liskov Substitution Principle

 Interface Segregation   ISP The Interface Segregation Principle

 Dependency Inversion     DIP The Dependency Inversion Principle


2. Here the author goes into detail about the Open/Closed Principle, which we've been applying unknowingly through the process of improving the awful DAO.

1) A class or module should be open for extension and closed for modification. 

2) Most APIs that define extensions via interfaces can be seen as following this principle.

3) It should have high cohesion and low coupling. 

- Cohesion: a single module or class is focused on a single responsibility or concern. 

- Coupling: the same principle can be applied at different scales — class, package, component, module.


This English version was translated by Claude.

zipstudy_spring190220_1.zipzipstudy_spring190220_2.zipzipstudy_spring190220_3.zip
친절한 찰쓰씨
Written by
친절한 찰쓰씨

Pleasant Charles — UI/UX researcher at AIT. Keeping notes on design, planning, and slow days here since 2010.

More on the author's page

Keep reading

Renewal

Steadily, for the long haul, without burning out

Mar 31, 2026·9 min
Renewal

Tech-life balance

Feb 7, 2026·3 min
Renewal

Humanality, by Park Jeong-ryeol

Feb 7, 2026·11 min