Skip to content

Add Service to Worker Pattern #2004

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ public class GiantModel {
private Fatigue fatigue;
private Nourishment nourishment;

GiantModel(Health health, Fatigue fatigue, Nourishment nourishment) {
/**
* Instantiates a new GiantModel.
*/
public GiantModel(Health health, Fatigue fatigue, Nourishment nourishment) {
this.health = health;
this.fatigue = fatigue;
this.nourishment = nourishment;
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@
<module>domain-model</module>
<module>composite-view</module>
<module>metadata-mapping</module>
<module>service-to-worker</module>
</modules>
<repositories>
<repository>
Expand Down
117 changes: 117 additions & 0 deletions service-to-worker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
---
layout: pattern
title: Service to Worker
folder: service-to-worker
permalink: /patterns/service-to-worker/
categories: Architectural
tags:
- Decoupling
---

## Intent

Combine a controller and dispatcher with views and helpers to handle client requests and prepare a dynamic presentation as the response. Controllers delegate content retrieval to helpers, which manage the population of the intermediate model for the view. A dispatcher is responsible for view management and navigation and can be encapsulated either within a controller or a separate component.

## Explanation

Real world example

> In the classic MVC pattern, M refers to the business model, V refers to the user interface, and C is the controller. The purpose of using MVC is to separate the implementation code of M and V, so that the same program can use different forms of expression. In the Service to Worker pattern, the C directly controls the display of the V and can receive commands to control the dispatcher indirectly. The dispatcher stores different commands that can be used to modify the `model` with `action`s or to modify the display in the `view`s.

In plain words

> Service to Worker Pattern uses Dispatcher to combine the controller and the view to handle client requests and prepare a dynamic presentation as the response.

**Programmatic Example**

We modified this pattern based on a classic design patterns [Model View Controller Pattern](https://github.com/iluwatar/java-design-patterns/tree/master/model-view-controller) as the Class Diagram and two main classes `Dispatcher` and `Action` have been added.

The Dispatcher, which encapsulates worker and view selection based on request information and/or an internal navigation model.

```java
public class Dispatcher {

private final GiantView giantView;
private final List<Action> actions;

/**
* Instantiates a new Dispatcher.
*
* @param giantView the giant view
*/
public Dispatcher(GiantView giantView) {
this.giantView = giantView;
this.actions = new ArrayList<>();
}

/**
* Add an action.
*
* @param action the action
*/
void addAction(Action action) {
actions.add(action);
}

/**
* Perform an action.
*
* @param s the s
* @param actionIndex the action index
*/
public void performAction(Command s, int actionIndex) {
actions.get(actionIndex).updateModel(s);
}

/**
* Update view.
*
* @param giantModel the giant model
*/
public void updateView(GiantModel giantModel) {
giantView.displayGiant(giantModel);
}
}
```

The Action (Worker), which can process user input and perform a specific update on the model.

```java
public class Action {

private final GiantModel giant;

/**
* Instantiates a new Action.
*
* @param giant the giant
*/
public Action(GiantModel giant) {
this.giant = giant;
}

/**
* Update model based on command.
*
* @param command the command
*/
public void updateModel(Command command) {
setFatigue(command.getFatigue());
setHealth(command.getHealth());
setNourishment(command.getNourishment());
}
}
```

Therefore, this example leverages the Service to Worker pattern to increase functionality cohesion and improve the business logic.


## Class diagram
![alt text](./etc/service-to-worker.png "Service to Worker")

## Applicability
- For the business logic of web development, the responsibility of a dispatcher component may be to translate the logical name login into the resource name of an appropriate view, such as login.jsp, and dispatch to that view. To accomplish this translation, the dispatcher may access resources such as an XML configuration file that specifies the appropriate view to display.

## Credits
* [J2EE Design Patterns](https://www.oreilly.com/library/view/j2ee-design-patterns/0596004273/re05.html)
* [Core J2EE Patterns](http://corej2eepatterns.com/Patterns/ServiceToWorker.htm)
Binary file added service-to-worker/etc/service-to-worker.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
86 changes: 86 additions & 0 deletions service-to-worker/etc/service-to-worker.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
@startuml
package com.iluwatar.servicetoworker {
class App {
+ App()
+ main(args : String[]) {static}
}
enum Health {
+ DEAD {static}
+ HEALTHY {static}
+ WOUNDED {static}
- title : String
+ toString() : String
}
enum Nourishment {
+ HUNGRY {static}
+ SATURATED {static}
+ STARVING {static}
- title : String
+ toString() : String
}
enum Fatigue {
+ ALERT {static}
+ SLEEPING {static}
+ TIRED {static}
- title : String
+ toString() : String
}

class GiantController {
- dispatcher : Dispatcher
+ GiantController(dispatcher : Dispatcher)
+ setCommand(s : Command, index : int)
+ updateView(giantModel : GiantModel)
}

class GiantModel {
- fatigue : Fatigue
- health : Health
- nourishment : Nourishment
# GiantModel(health : Health, fatigue : Fatigue, nourishment : Nourishment)
+ getFatigue() : Fatigue
+ getHealth() : Health
+ getNourishment() : Nourishment
+ setFatigue(fatigue : Fatigue)
+ setHealth(health : Health)
+ setNourishment(nourishment : Nourishment)
+ toString() : String
}
class GiantView {
- LOGGER : Logger {static}
+ GiantView()
+ displayGiant(giant : GiantModel)
}

class Action{
- giant : GiantModel
+ Action(giant: GiantModel)
+ updateModel(command: Command)
+ setHealth(health : Health)
+ setFatigue(fatigue : Fatigue)
+ setNourishment(nourishment : Nourishment)
}

class Dispatcher{
- giantView : GiantView
- actions : ArrayList<Action>
+ Dispatcher(giantView : GiantView)
+ addAction(action: Action)
+ performAction(s: Command, actionIndex: int)
+ updateView(giant : GiantModel)
}
}
GiantModel --> Nourishment
GiantModel --> Fatigue
GiantModel --> Health

GiantView ..> GiantModel
Dispatcher o-up- Action
GiantController -up-> Dispatcher

GiantController .up.> GiantModel
Action --> GiantModel
Dispatcher -up-> GiantView
Dispatcher .left.> GiantModel

@enduml
46 changes: 46 additions & 0 deletions service-to-worker/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.26.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>service-to-worker</artifactId>

<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.iluwatar</groupId>
<artifactId>model-view-controller</artifactId>
<version>1.26.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<configuration>
<archive>
<manifest>
<mainClass>com.iluwatar.servicetoworker.App</mainClass>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.iluwatar.servicetoworker;

import com.iluwatar.model.view.controller.Fatigue;
import com.iluwatar.model.view.controller.Health;
import com.iluwatar.model.view.controller.Nourishment;

/**
* The type Action (Worker), which can process user input and perform a specific update on the
* model.
*/
public class Action {

public GiantModel giant;

/**
* Instantiates a new Action.
*
* @param giant the giant
*/
public Action(GiantModel giant) {
this.giant = giant;
}

/**
* Update model based on command.
*
* @param command the command
*/
public void updateModel(Command command) {
setFatigue(command.getFatigue());
setHealth(command.getHealth());
setNourishment(command.getNourishment());
}

/**
* Sets health.
*
* @param health the health
*/
public void setHealth(Health health) {
giant.setHealth(health);
}

/**
* Sets fatigue.
*
* @param fatigue the fatigue
*/
public void setFatigue(Fatigue fatigue) {
giant.setFatigue(fatigue);
}

/**
* Sets nourishment.
*
* @param nourishment the nourishment
*/
public void setNourishment(Nourishment nourishment) {
giant.setNourishment(nourishment);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.iluwatar.servicetoworker;

import com.iluwatar.model.view.controller.Fatigue;
import com.iluwatar.model.view.controller.Health;
import com.iluwatar.model.view.controller.Nourishment;

/**
* The front controller intercepts all requests and performs common functions using decorators. The
* front controller passes request information to the dispatcher, which uses the request and an
* internal model to chooses and execute appropriate actions. The actions process user input,
* translating it into appropriate updates to the model. The model applies business rules and stores
* the data persistently. Based on the user input and results of the actions, the dispatcher chooses
* a view. The view transforms the updated model data into a form suitable for the user.
*/
public class App {

/**
* Program entry point.
*
* @param args command line args
*/
public static void main(String[] args) {
// create model, view and controller
var giant1 = new GiantModel("giant1", Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
var giant2 = new GiantModel("giant2", Health.DEAD, Fatigue.SLEEPING, Nourishment.STARVING);
var action1 = new Action(giant1);
var action2 = new Action(giant2);
var view = new GiantView();
var dispatcher = new Dispatcher(view);
dispatcher.addAction(action1);
dispatcher.addAction(action2);
var controller = new GiantController(dispatcher);

// initial display
controller.updateView(giant1);
controller.updateView(giant2);

// controller receives some interactions that affect the giant
controller.setCommand(new Command(Fatigue.SLEEPING, Health.HEALTHY, Nourishment.STARVING), 0);
controller.setCommand(new Command(Fatigue.ALERT, Health.HEALTHY, Nourishment.HUNGRY), 1);

// redisplay
controller.updateView(giant1);
controller.updateView(giant2);
// controller receives some interactions that affect the giant
}
}
Loading