#590 explanation for Service Layer
This commit is contained in:
		@@ -9,12 +9,210 @@ tags:
 | 
				
			|||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Intent
 | 
					## Intent
 | 
				
			||||||
Service Layer is an abstraction over domain logic. Typically
 | 
					
 | 
				
			||||||
applications require multiple kinds of interfaces to the data they store and
 | 
					Service Layer is an abstraction over domain logic. It defines application's boundary with a layer of services that 
 | 
				
			||||||
logic they implement: data loaders, user interfaces, integration gateways, and
 | 
					establishes a set of available operations and coordinates the application's response in each operation.
 | 
				
			||||||
others. Despite their different purposes, these interfaces often need common
 | 
					
 | 
				
			||||||
interactions with the application to access and manipulate its data and invoke
 | 
					## Explanation
 | 
				
			||||||
its business logic. The Service Layer fulfills this role.
 | 
					
 | 
				
			||||||
 | 
					Typically applications require different kinds of interfaces to the data they store and the logic they implement. 
 | 
				
			||||||
 | 
					Despite their different purposes, these interfaces often need common interactions with the application to access and 
 | 
				
			||||||
 | 
					manipulate its data and invoke its business logic. Encoding the logic of the interactions separately in each module 
 | 
				
			||||||
 | 
					causes a lot of duplication. It's better to centralize building the business logic inside single Service Layer to avoid 
 | 
				
			||||||
 | 
					these pitfalls.
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					Real world example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> We are writing an application that tracks wizards, spellbooks and spells. Wizards may have spellbooks and spellbooks 
 | 
				
			||||||
 | 
					may have spells.           
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In plain words
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> Service Layer is an abstraction over application's business logic.   
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Wikipedia says
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Programmatic Example**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The example application demonstrates interactions between a client `App` and a service `MagicService` that allows
 | 
				
			||||||
 | 
					interaction between wizards, spellbooks and spells. The service is implemented with 3-layer architecture 
 | 
				
			||||||
 | 
					(entity, dao, service).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For this explanation we are looking at one vertical slice of the system. Let's start from the entity layer and look at 
 | 
				
			||||||
 | 
					`Wizard` class. Other entities not shown here are `Spellbook` and `Spell`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					@Entity
 | 
				
			||||||
 | 
					@Table(name = "WIZARD")
 | 
				
			||||||
 | 
					public class Wizard extends BaseEntity {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Id
 | 
				
			||||||
 | 
					  @GeneratedValue
 | 
				
			||||||
 | 
					  @Column(name = "WIZARD_ID")
 | 
				
			||||||
 | 
					  private Long id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private String name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @ManyToMany(cascade = CascadeType.ALL)
 | 
				
			||||||
 | 
					  private Set<Spellbook> spellbooks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public Wizard() {
 | 
				
			||||||
 | 
					    spellbooks = new HashSet<>();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public Wizard(String name) {
 | 
				
			||||||
 | 
					    this();
 | 
				
			||||||
 | 
					    this.name = name;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public Long getId() {
 | 
				
			||||||
 | 
					    return id;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void setId(Long id) {
 | 
				
			||||||
 | 
					    this.id = id;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public String getName() {
 | 
				
			||||||
 | 
					    return name;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void setName(String name) {
 | 
				
			||||||
 | 
					    this.name = name;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public Set<Spellbook> getSpellbooks() {
 | 
				
			||||||
 | 
					    return spellbooks;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void setSpellbooks(Set<Spellbook> spellbooks) {
 | 
				
			||||||
 | 
					    this.spellbooks = spellbooks;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public void addSpellbook(Spellbook spellbook) {
 | 
				
			||||||
 | 
					    spellbook.getWizards().add(this);
 | 
				
			||||||
 | 
					    spellbooks.add(spellbook);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public String toString() {
 | 
				
			||||||
 | 
					    return name;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Above the entity layer we have DAOs. For `Wizard` the DAO layer looks as follows.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					public interface WizardDao extends Dao<Wizard> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Wizard findByName(String name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class WizardDaoImpl extends DaoBaseImpl<Wizard> implements WizardDao {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public Wizard findByName(String name) {
 | 
				
			||||||
 | 
					    Transaction tx = null;
 | 
				
			||||||
 | 
					    Wizard result;
 | 
				
			||||||
 | 
					    try (var session = getSessionFactory().openSession()) {
 | 
				
			||||||
 | 
					      tx = session.beginTransaction();
 | 
				
			||||||
 | 
					      var criteria = session.createCriteria(persistentClass);
 | 
				
			||||||
 | 
					      criteria.add(Restrictions.eq("name", name));
 | 
				
			||||||
 | 
					      result = (Wizard) criteria.uniqueResult();
 | 
				
			||||||
 | 
					      tx.commit();
 | 
				
			||||||
 | 
					    } catch (Exception e) {
 | 
				
			||||||
 | 
					      if (tx != null) {
 | 
				
			||||||
 | 
					        tx.rollback();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      throw e;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Next we can look at the Service Layer, which in our case consists of a single `MagicService`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					public interface MagicService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  List<Wizard> findAllWizards();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  List<Spellbook> findAllSpellbooks();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  List<Spell> findAllSpells();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  List<Wizard> findWizardsWithSpellbook(String name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  List<Wizard> findWizardsWithSpell(String name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class MagicServiceImpl implements MagicService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private WizardDao wizardDao;
 | 
				
			||||||
 | 
					  private SpellbookDao spellbookDao;
 | 
				
			||||||
 | 
					  private SpellDao spellDao;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public MagicServiceImpl(WizardDao wizardDao, SpellbookDao spellbookDao, SpellDao spellDao) {
 | 
				
			||||||
 | 
					    this.wizardDao = wizardDao;
 | 
				
			||||||
 | 
					    this.spellbookDao = spellbookDao;
 | 
				
			||||||
 | 
					    this.spellDao = spellDao;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public List<Wizard> findAllWizards() {
 | 
				
			||||||
 | 
					    return wizardDao.findAll();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public List<Spellbook> findAllSpellbooks() {
 | 
				
			||||||
 | 
					    return spellbookDao.findAll();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public List<Spell> findAllSpells() {
 | 
				
			||||||
 | 
					    return spellDao.findAll();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public List<Wizard> findWizardsWithSpellbook(String name) {
 | 
				
			||||||
 | 
					    var spellbook = spellbookDao.findByName(name);
 | 
				
			||||||
 | 
					    return new ArrayList<>(spellbook.getWizards());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public List<Wizard> findWizardsWithSpell(String name) {
 | 
				
			||||||
 | 
					    var spell = spellDao.findByName(name);
 | 
				
			||||||
 | 
					    var spellbook = spell.getSpellbook();
 | 
				
			||||||
 | 
					    return new ArrayList<>(spellbook.getWizards());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					And finally we can show how the client `App` interacts with `MagicService` in the Service Layer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```java
 | 
				
			||||||
 | 
					    var service = new MagicServiceImpl(wizardDao, spellbookDao, spellDao);
 | 
				
			||||||
 | 
					    LOGGER.info("Enumerating all wizards");
 | 
				
			||||||
 | 
					    service.findAllWizards().stream().map(Wizard::getName).forEach(LOGGER::info);
 | 
				
			||||||
 | 
					    LOGGER.info("Enumerating all spellbooks");
 | 
				
			||||||
 | 
					    service.findAllSpellbooks().stream().map(Spellbook::getName).forEach(LOGGER::info);
 | 
				
			||||||
 | 
					    LOGGER.info("Enumerating all spells");
 | 
				
			||||||
 | 
					    service.findAllSpells().stream().map(Spell::getName).forEach(LOGGER::info);
 | 
				
			||||||
 | 
					    LOGGER.info("Find wizards with spellbook 'Book of Idores'");
 | 
				
			||||||
 | 
					    var wizardsWithSpellbook = service.findWizardsWithSpellbook("Book of Idores");
 | 
				
			||||||
 | 
					    wizardsWithSpellbook.forEach(w -> LOGGER.info("{} has 'Book of Idores'", w.getName()));
 | 
				
			||||||
 | 
					    LOGGER.info("Find wizards with spell 'Fireball'");
 | 
				
			||||||
 | 
					    var wizardsWithSpell = service.findWizardsWithSpell("Fireball");
 | 
				
			||||||
 | 
					    wizardsWithSpell.forEach(w -> LOGGER.info("{} has 'Fireball'", w.getName()));
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Class diagram
 | 
					## Class diagram
 | 
				
			||||||

 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user