Skip to content

Commit a8ac5d4

Browse files
committed
Layer Supertype Pattern #1302
Implemented the Layer Supertype Pattern in Service Layer, updated README file and PUML class diagram to reflect the new changes.
1 parent adbddcb commit a8ac5d4

File tree

14 files changed

+73
-152
lines changed

14 files changed

+73
-152
lines changed

service-layer/README.md

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ Wikipedia says
3636

3737
> Service layer is an architectural pattern, applied within the service-orientation design paradigm, which aims to organize the services, within a service inventory, into a set of logical layers. Services that are categorized into a particular layer share functionality. This helps to reduce the conceptual overhead related to managing the service inventory, as the services belonging to the same layer address a smaller set of activities.
3838
39+
## Application of Layer Supertype Pattern in This Example
40+
41+
The `Layer Supertype` pattern is used in this implementation to provide a common base class for all entities (`BaseEntity`) and DAOs (`DaoBaseImpl`). This pattern helps reduce redundancy by defining shared properties and methods in a superclass that all child classes can inherit.
42+
43+
### Layer Supertype in the Entity Layer
44+
45+
The `BaseEntity` class serves as the common base class for all entities, providing shared attributes like `id`. This ensures consistent handling of these attributes across different entity classes like `Wizard`, `Spellbook`, and `Spell`.
46+
47+
### Layer Supertype in the DAO Layer
48+
49+
In the DAO layer, the `DaoBaseImpl` class acts as a common base implementation for all DAO classes, offering shared functionalities such as session handling and basic CRUD operations. By inheriting from `DaoBaseImpl`, specific DAO implementations like `WizardDaoImpl` can focus solely on their unique logic, while reusing common functionality.
50+
3951
## Programmatic Example of Service Layer Pattern in Java
4052

4153
Our Java implementation uses the Service Layer pattern to streamline interactions between data access objects (DAOs) and the business logic, ensuring a clean separation of concerns.
@@ -88,32 +100,13 @@ Above the entity layer we have DAOs. For `Wizard` the DAO layer looks as follows
88100

89101
```java
90102
public interface WizardDao extends Dao<Wizard> {
91-
92-
Wizard findByName(String name);
103+
93104
}
94105
```
95106

96107
```java
97108
public class WizardDaoImpl extends DaoBaseImpl<Wizard> implements WizardDao {
98-
99-
@Override
100-
public Wizard findByName(String name) {
101-
Transaction tx = null;
102-
Wizard result;
103-
try (var session = getSessionFactory().openSession()) {
104-
tx = session.beginTransaction();
105-
var criteria = session.createCriteria(persistentClass);
106-
criteria.add(Restrictions.eq("name", name));
107-
result = (Wizard) criteria.uniqueResult();
108-
tx.commit();
109-
} catch (Exception e) {
110-
if (tx != null) {
111-
tx.rollback();
112-
}
113-
throw e;
114-
}
115-
return result;
116-
}
109+
117110
}
118111
```
119112

@@ -379,13 +372,19 @@ Implementing a Service Layer in Java
379372
* Enhances testability by isolating business logic.
380373
* Improves maintainability and flexibility of enterprise applications.
381374

375+
Using the Layer Supertype pattern in conjunction:
376+
377+
* Reduces boilerplate code by centralizing common logic.
378+
* Increases consistency across layers, simplifying debugging and enhancement.
379+
382380
Trade-offs:
383381

384382
* May introduce additional complexity by adding another layer to the application.
385383
* Can result in performance overhead due to the extra layer of abstraction.
386384

387385
## Related Java Design Patterns
388386

387+
* [Layer Supertype](https://martinfowler.com/eaaCatalog/layerSupertype.html): Helps reduce duplication in entities and DAOs by centralizing common logic.
389388
* [Facade](https://java-design-patterns.com/patterns/facade/): Simplifies interactions with complex subsystems by providing a unified interface.
390389
* [DAO (Data Access Object)](https://java-design-patterns.com/patterns/dao/): Often used together with the Service Layer to handle data persistence.
391390
* [MVC (Model-View-Controller)](https://java-design-patterns.com/patterns/model-view-controller/): The Service Layer can be used to encapsulate business logic in the model component.
@@ -396,3 +395,4 @@ Trade-offs:
396395
* [Patterns of Enterprise Application Architecture](https://amzn.to/3WfKBPR)
397396
* [Spring in Action](https://amzn.to/4asnpSG)
398397
* [Service Layer (Martin Fowler)](http://martinfowler.com/eaaCatalog/serviceLayer.html)
398+
* [Layer Supertype (Martin Fowler)](https://martinfowler.com/eaaCatalog/layerSupertype.html)

service-layer/etc/service-layer.urm.puml

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ package com.iluwatar.servicelayer.common {
2222
+ findAll() : List<E extends BaseEntity> {abstract}
2323
+ merge(E extends BaseEntity) : E extends BaseEntity {abstract}
2424
+ persist(E extends BaseEntity) {abstract}
25+
+ findByName(String) : E extends BaseEntity {abstract}
2526
}
2627
abstract class DaoBaseImpl<E extends BaseEntity> {
2728
# persistentClass : Class<E extends BaseEntity>
2829
+ DaoBaseImpl<E extends BaseEntity>()
2930
+ delete(entity : E extends BaseEntity)
3031
+ find(id : Long) : E extends BaseEntity
3132
+ findAll() : List<E extends BaseEntity>
33+
+ findByName(name : String) : E extends BaseEntity
3234
# getSessionFactory() : SessionFactory
3335
+ merge(entity : E extends BaseEntity) : E extends BaseEntity
3436
+ persist(entity : E extends BaseEntity)
@@ -71,11 +73,9 @@ package com.iluwatar.servicelayer.wizard {
7173
+ toString() : String
7274
}
7375
interface WizardDao {
74-
+ findByName(String) : Wizard {abstract}
7576
}
7677
class WizardDaoImpl {
7778
+ WizardDaoImpl()
78-
+ findByName(name : String) : Wizard
7979
}
8080
}
8181
package com.iluwatar.servicelayer.spellbook {
@@ -98,11 +98,9 @@ package com.iluwatar.servicelayer.spellbook {
9898
+ toString() : String
9999
}
100100
interface SpellbookDao {
101-
+ findByName(String) : Spellbook {abstract}
102101
}
103102
class SpellbookDaoImpl {
104103
+ SpellbookDaoImpl()
105-
+ findByName(name : String) : Spellbook
106104
}
107105
}
108106
package com.iluwatar.servicelayer.spell {
@@ -121,11 +119,9 @@ package com.iluwatar.servicelayer.spell {
121119
+ toString() : String
122120
}
123121
interface SpellDao {
124-
+ findByName(String) : Spell {abstract}
125122
}
126123
class SpellDaoImpl {
127124
+ SpellDaoImpl()
128-
+ findByName(name : String) : Spell
129125
}
130126
}
131127
package com.iluwatar.servicelayer.app {
@@ -142,18 +138,18 @@ MagicServiceImpl --> "-spellbookDao" SpellbookDao
142138
MagicServiceImpl --> "-spellDao" SpellDao
143139
Spellbook --> "-spells" Spell
144140
Spellbook --> "-wizards" Wizard
145-
DaoBaseImpl ..|> Dao
146-
MagicServiceImpl ..|> MagicService
147-
Spell --|> BaseEntity
148-
SpellDao --|> Dao
149-
SpellDaoImpl ..|> SpellDao
150-
SpellDaoImpl --|> DaoBaseImpl
151-
Spellbook --|> BaseEntity
152-
SpellbookDao --|> Dao
153-
SpellbookDaoImpl ..|> SpellbookDao
154-
SpellbookDaoImpl --|> DaoBaseImpl
155-
Wizard --|> BaseEntity
156-
WizardDao --|> Dao
157-
WizardDaoImpl ..|> WizardDao
158-
WizardDaoImpl --|> DaoBaseImpl
159-
@enduml
141+
DaoBaseImpl ..|> Dao
142+
MagicServiceImpl ..|> MagicService
143+
Spell --|> BaseEntity
144+
SpellDao --|> Dao
145+
SpellDaoImpl ..|> SpellDao
146+
SpellDaoImpl --|> DaoBaseImpl
147+
Spellbook --|> BaseEntity
148+
SpellbookDao --|> Dao
149+
SpellbookDaoImpl ..|> SpellbookDao
150+
SpellbookDaoImpl --|> DaoBaseImpl
151+
Wizard --|> BaseEntity
152+
WizardDao --|> Dao
153+
WizardDaoImpl ..|> WizardDao
154+
WizardDaoImpl --|> DaoBaseImpl
155+
@enduml

service-layer/src/main/java/com/iluwatar/servicelayer/common/Dao.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ public interface Dao<E extends BaseEntity> {
4242
void delete(E entity);
4343

4444
List<E> findAll();
45+
46+
E findByName(String name);
4547
}

service-layer/src/main/java/com/iluwatar/servicelayer/common/DaoBaseImpl.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,27 @@ public E find(Long id) {
7474
}
7575
return result;
7676
}
77+
@Override
78+
public E findByName(String name) {
79+
Transaction tx = null;
80+
E result;
81+
try (var session = getSessionFactory().openSession()) {
82+
tx = session.beginTransaction();
83+
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
84+
CriteriaQuery<E> builderQuery = criteriaBuilder.createQuery(persistentClass);
85+
Root<E> root = builderQuery.from(persistentClass);
86+
builderQuery.select(root).where(criteriaBuilder.equal(root.get("name"), name));
87+
Query<E> query = session.createQuery(builderQuery);
88+
result = query.uniqueResult();
89+
tx.commit();
90+
} catch (Exception e) {
91+
if (tx != null) {
92+
tx.rollback();
93+
}
94+
throw e;
95+
}
96+
return result;
97+
}
7798

7899
@Override
79100
public void persist(E entity) {

service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDao.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,5 @@
3131
*/
3232
public interface SpellDao extends Dao<Spell> {
3333

34-
Spell findByName(String name);
3534

3635
}

service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDaoImpl.java

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,4 @@
3737
*/
3838
public class SpellDaoImpl extends DaoBaseImpl<Spell> implements SpellDao {
3939

40-
@Override
41-
public Spell findByName(String name) {
42-
Transaction tx = null;
43-
Spell result;
44-
try (var session = getSessionFactory().openSession()) {
45-
tx = session.beginTransaction();
46-
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
47-
CriteriaQuery<Spell> builderQuery = criteriaBuilder.createQuery(Spell.class);
48-
Root<Spell> root = builderQuery.from(Spell.class);
49-
builderQuery.select(root).where(criteriaBuilder.equal(root.get("name"), name));
50-
Query<Spell> query = session.createQuery(builderQuery);
51-
result = query.uniqueResult();
52-
tx.commit();
53-
} catch (Exception e) {
54-
if (tx != null) {
55-
tx.rollback();
56-
}
57-
throw e;
58-
}
59-
return result;
60-
}
6140
}

service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/SpellbookDao.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,4 @@
3131
*/
3232
public interface SpellbookDao extends Dao<Spellbook> {
3333

34-
Spellbook findByName(String name);
35-
3634
}

service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/SpellbookDaoImpl.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,26 +37,4 @@
3737
*/
3838
public class SpellbookDaoImpl extends DaoBaseImpl<Spellbook> implements SpellbookDao {
3939

40-
@Override
41-
public Spellbook findByName(String name) {
42-
Transaction tx = null;
43-
Spellbook result;
44-
try (var session = getSessionFactory().openSession()) {
45-
tx = session.beginTransaction();
46-
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
47-
CriteriaQuery<Spellbook> builderQuery = criteriaBuilder.createQuery(Spellbook.class);
48-
Root<Spellbook> root = builderQuery.from(Spellbook.class);
49-
builderQuery.select(root).where(criteriaBuilder.equal(root.get("name"), name));
50-
Query<Spellbook> query = session.createQuery(builderQuery);
51-
result = query.uniqueResult();
52-
tx.commit();
53-
} catch (Exception e) {
54-
if (tx != null) {
55-
tx.rollback();
56-
}
57-
throw e;
58-
}
59-
return result;
60-
}
61-
6240
}

service-layer/src/main/java/com/iluwatar/servicelayer/wizard/WizardDao.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,4 @@
3131
*/
3232
public interface WizardDao extends Dao<Wizard> {
3333

34-
Wizard findByName(String name);
35-
3634
}

service-layer/src/main/java/com/iluwatar/servicelayer/wizard/WizardDaoImpl.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,26 +35,4 @@
3535
* WizardDao implementation.
3636
*/
3737
public class WizardDaoImpl extends DaoBaseImpl<Wizard> implements WizardDao {
38-
39-
@Override
40-
public Wizard findByName(String name) {
41-
Transaction tx = null;
42-
Wizard result;
43-
try (var session = getSessionFactory().openSession()) {
44-
tx = session.beginTransaction();
45-
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
46-
CriteriaQuery<Wizard> builderQuery = criteriaBuilder.createQuery(Wizard.class);
47-
Root<Wizard> root = builderQuery.from(Wizard.class);
48-
builderQuery.select(root).where(criteriaBuilder.equal(root.get("name"), name));
49-
Query<Wizard> query = session.createQuery(builderQuery);
50-
result = query.uniqueResult();
51-
tx.commit();
52-
} catch (Exception e) {
53-
if (tx != null) {
54-
tx.rollback();
55-
}
56-
throw e;
57-
}
58-
return result;
59-
}
6038
}

0 commit comments

Comments
 (0)