Hexagon architecture

An example of Hexagon architecture in java.
This commit is contained in:
Philippe Soares 2019-11-20 02:46:33 -05:00
parent 5095a8fc6a
commit 32ee0232f0
10 changed files with 224 additions and 0 deletions

View File

@ -1,3 +1,4 @@
### Relevant Articles:
- [Service Locator Pattern](https://www.baeldung.com/java-service-locator-pattern)
- [The DAO Pattern in Java](https://www.baeldung.com/java-dao-pattern)
- [A Practical Example of Hexagonal Architecture in Java](https://www.baeldung.com/java-hexagonal-pattern)

View File

@ -0,0 +1,45 @@
package com.baeldung.hexagonal;
import com.baeldung.hexagonal.adapters.DisplayInConsoleAdapter;
import com.baeldung.hexagonal.adapters.InMemoryMessageStore;
import com.baeldung.hexagonal.application.ChatManager;
import com.baeldung.hexagonal.domain.ChatUser;
import com.baeldung.hexagonal.domain.IDisplayMessages;
import java.util.ArrayDeque;
import java.util.Scanner;
public class ChatApplication {
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
System.out.print("Enter username of user 1: ");
ChatUser user1 = new ChatUser(console.nextLine());
System.out.printf("Enter username of user 2: ");
ChatUser user2 = new ChatUser(console.nextLine());
System.out.println("Chat will end when any user uses the word bye in a message.");
InMemoryMessageStore messageStore = new InMemoryMessageStore(new ArrayDeque<>(10));
IDisplayMessages messageDisplayer = new DisplayInConsoleAdapter(messageStore);
ChatManager chatManager = new ChatManager(messageStore, messageDisplayer);
while (true) {
System.out.printf("From %s to %s : ", user1, user2);
String message = console.nextLine();
if (message.toLowerCase().contains("bye")) {
chatManager.sendMessage(user1, user2, message);
System.out.println("Chat recap:");
messageDisplayer.displayMessages();
System.exit(0);
}
chatManager.sendMessage(user1, user2, message);
ChatUser temp = user1;
user1 = user2;
user2 = temp;
}
}
}

View File

@ -0,0 +1,36 @@
package com.baeldung.hexagonal.adapters;
import com.baeldung.hexagonal.domain.ChatMessage;
import com.baeldung.hexagonal.domain.IDisplayMessages;
import com.baeldung.hexagonal.domain.IStoreMessages;
/**
* A Utility adapter to display the chat messages in the console
*/
public class DisplayInConsoleAdapter implements IDisplayMessages {
IStoreMessages messageStore;
public DisplayInConsoleAdapter(IStoreMessages messageStore) {
this.messageStore = messageStore;
}
public static void clearScreen() {
System.out.print("\033[H\033[2J");
System.out.flush();
}
@Override
public void displayMessages() {
clearScreen();
for (ChatMessage message: messageStore.getMessages(10)) {
System.out.printf(
"%tF %tT [%s to %s]: %s %n",
message.getTimeSent(),
message.getTimeSent(),
message.getFrom(),
message.getTo(),
message.getContents());
}
}
}

View File

@ -0,0 +1,37 @@
package com.baeldung.hexagonal.adapters;
import com.baeldung.hexagonal.domain.ChatMessage;
import com.baeldung.hexagonal.domain.IStoreMessages;
import java.util.Collection;
import java.util.Comparator;
import java.util.Queue;
import java.util.stream.Collectors;
/**
* We're storing the messages in memory. We could later opt to switch to an implementation that stores messages in a
* database.
*/
public class InMemoryMessageStore implements IStoreMessages {
private Queue<ChatMessage> messages;
public InMemoryMessageStore(Queue<ChatMessage> messages) {
this.messages = messages;
}
@Override
public void storeMessage(ChatMessage message) {
this.messages.add(message);
}
@Override
public Collection<ChatMessage> getMessages(long maxNbMessages) {// @formatter:off
return messages.stream()
.sorted((m1, m2) -> m2.getTimeSent().compareTo(m1.getTimeSent()))
.limit(maxNbMessages)
.sorted(Comparator.comparing(ChatMessage::getTimeSent))
.collect(Collectors.toList());
// @formatter:on
}
}

View File

@ -0,0 +1,27 @@
package com.baeldung.hexagonal.application;
import com.baeldung.hexagonal.domain.*;
import java.time.LocalDateTime;
public class ChatManager implements ISendMessage {
// The domain doesn't need to know where messages will be stored
private IStoreMessages messageStore;
// The domain doesn't need to know how messages will be displayed
private IDisplayMessages messageDisplayer;
public ChatManager(IStoreMessages messageStore, IDisplayMessages displayMessages) {
this.messageStore = messageStore;
this.messageDisplayer = displayMessages;
}
@Override
public void sendMessage(ChatUser from, ChatUser to, String message) {
ChatMessage chatMessage = new ChatMessage(LocalDateTime.now(), from, to, message);
this.messageStore.storeMessage(chatMessage);
this.messageDisplayer.displayMessages();
}
}

View File

@ -0,0 +1,34 @@
package com.baeldung.hexagonal.domain;
import java.time.LocalDateTime;
public class ChatMessage {
private LocalDateTime timeSent;
private ChatUser from;
private ChatUser to;
private String contents;
public LocalDateTime getTimeSent() {
return timeSent;
}
public ChatUser getFrom() {
return from;
}
public ChatUser getTo() {
return to;
}
public String getContents() {
return contents;
}
public ChatMessage(LocalDateTime timeSent, ChatUser from, ChatUser to, String contents) {
this.timeSent = timeSent;
this.from = from;
this.to = to;
this.contents = contents;
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.hexagonal.domain;
public class ChatUser {
private String name;
public ChatUser(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}

View File

@ -0,0 +1,8 @@
package com.baeldung.hexagonal.domain;
/**
* An external system displays the messages sent by users.
*/
public interface IDisplayMessages {
void displayMessages();
}

View File

@ -0,0 +1,8 @@
package com.baeldung.hexagonal.domain;
/**
* A user sends a message (application's use case)
*/
public interface ISendMessage {
void sendMessage(ChatUser from, ChatUser to, String message);
}

View File

@ -0,0 +1,14 @@
package com.baeldung.hexagonal.domain;
import java.util.Collection;
/**
* An external system (infrastructure) stores a message
*/
public interface IStoreMessages {
void storeMessage(ChatMessage message);
Collection<ChatMessage> getMessages(long maxNbMessages);
}