* update yaml frontmatter format * update abstract document * update abstract factory * use the new pattern template * acyclic visitor seo * adapter seo * ambassador seo * acl seo * aaa seo * async method invocation seo * balking seo * bridge seo * builder seo * business delegate and bytecode seo * caching seo * callback seo * chain seo * update headings * circuit breaker seo * client session + collecting parameter seo * collection pipeline seo * combinator SEO * command seo * cqrs seo * commander seo * component seo * composite seo * composite entity seo * composite view seo * context object seo * converter seo * crtp seo * currying seo * dao seo * data bus seo * data locality seo * data mapper seo * dto seo * decorator seo * delegation seo * di seo * dirty flag seo * domain model seo * double buffer seo * double checked locking seo * double dispatch seo * dynamic proxy seo * event aggregator seo * event-based asynchronous seo * eda seo * event queue seo * event sourcing seo * execute around seo * extension objects seo * facade seo * factory seo * factory kit seo * factory method seo * fanout/fanin seo * feature toggle seo * filterer seo * fluent interface seo * flux seo * flyweight seo * front controller seo * function composition seo * game loop seo * gateway seo * guarded suspension seo * half-sync/half-async seo * health check seo * hexagonal seo * identity map seo * intercepting filter seo * interpreter seo * iterator seo * layers seo * lazy loading seo * leader election seo * leader/followers seo * lockable object seo * rename and add seo for marker interface * master-worker seo * mediator seo * memento seo * metadata mapping seo * microservice aggregator seo * api gw seo * microservices log aggregration seo * mvc seo * mvi seo * mvp seo * mvvm seo * monad seo * monitor seo * monostate seo * multiton seo * mute idiom seo * naked objects & notification seo * null object seo * object mother seo * object pool seo * observer seo * optimistic locking seo * page controller seo * page object seo * parameter object seo * partial response seo * pipeline seo * poison pill seo * presentation model seo * private class data seo * producer-consumer seo * promise seo * property seo * prototype seo * proxy seo * queue-based load leveling seo * reactor seo * registry seo * repository seo * RAII seo * retry seo * role object seo * saga seo * separated interface seo * serialized entity seo * serialized lob seo * servant seo * server session seo * service layer seo * service locator seo * service to worker seo * sharding seo * single table inheritance seo * singleton seo * spatial partition seo * special case seo * specification seo * state seo * step builder seo * strangler seo * strategy seo * subclass sandbox seo * table module seo * template method seo * throttling seo * tolerant reader seo * trampoline seo * transaction script seo * twin seo * type object seo * unit of work seo * update method seo * value object seo * version number seo * virtual proxy seo * visitor seo * seo enhancements * seo improvements * SEO enhancements * SEO improvements * SEO additions * SEO improvements * more SEO improvements * rename hexagonal + SEO improvements * SEO improvements * more SEO stuff * SEO improvements * SEO optimizations * SEO enhancements * enchance SEO * improve SEO * SEO improvements * update headers
8.3 KiB
title, shortTitle, description, category, language, tag
| title | shortTitle | description | category | language | tag | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Role Object Pattern in Java: Enhancing Flexibility in Object Roles and Behaviors | Role Object | Explore the Role Object design pattern in Java, which allows objects to dynamically assume various roles, enhancing flexibility and system adaptability. Ideal for developers looking to implement dynamic behavior in applications. | Structural | en |
|
Intent of Role Object Design Pattern
Efficiently assign dynamic roles to Java objects, enabling them to adapt behaviors and responsibilities on-the-fly, optimizing runtime flexibility.
Detailed Explanation of Role Object Pattern with Real-World Examples
Real-world example
Imagine a restaurant where staff members can take on different roles based on the needs of the moment. For example, an employee could be a server, a cashier, or a kitchen helper depending on the situation. When the restaurant is busy, a server might also take on the role of a cashier to help process payments quickly. Later, the same employee might assist in the kitchen during a rush. This flexibility allows the restaurant to dynamically allocate responsibilities to meet real-time demands, enhancing efficiency and customer satisfaction. The Role Object pattern in software mimics this by allowing objects to assume different roles and behaviors at runtime, providing similar flexibility and adaptability.
In plain words
The Role Object pattern in Java models context-specific views through separate, dynamically managed role objects, enhancing modular design and runtime adaptability.
wiki.c2.com says
Adapt an object to different client’s needs through transparently attached role objects, each one representing a role the object has to play in that client’s context. The object manages its role set dynamically. By representing roles as individual objects, different contexts are kept separate and system configuration is simplified.
Programmatic Example of Role Object Pattern in Java
The Role Object design pattern is a pattern that suggests modeling context-specific views of an object as separate role objects. These role objects are dynamically attached to and removed from the core object. The resulting composite object structure, consisting of the core and its role objects, is called a subject. A subject often plays several roles and the same role is likely to be played by different subjects.
In the provided code, we have a Customer object that can play different roles such as Borrower and Investor. These roles are represented by BorrowerRole and InvestorRole classes respectively, which extend the CustomerRole class.
Here is the Customer class:
public abstract class Customer {
public abstract boolean addRole(Role role);
public abstract boolean hasRole(Role role);
public abstract boolean remRole(Role role);
public abstract <T extends Customer> Optional<T> getRole(Role role, Class<T> expectedRole);
public static Customer newCustomer() {
return new CustomerCore();
}
public static Customer newCustomer(Role... role) {
var customer = newCustomer();
Arrays.stream(role).forEach(customer::addRole);
return customer;
}
}
Here is the BorrowerRole class:
@Getter
@Setter
public class BorrowerRole extends CustomerRole {
private String name;
public String borrow() {
return String.format("Borrower %s wants to get some money.", name);
}
}
In this class, the borrow method represents an operation specific to the Borrower role.
Similarly, the InvestorRole class represents the Investor role:
@Getter
@Setter
public class InvestorRole extends CustomerRole {
private String name;
private long amountToInvest;
public String invest() {
return String.format("Investor %s has invested %d dollars", name, amountToInvest);
}
}
In the InvestorRole class, the invest method represents an operation specific to the Investor role.
The Customer object can play either of these roles or both. This is demonstrated in the main function:
public static void main(String[] args) {
var customer = Customer.newCustomer(BORROWER, INVESTOR);
LOGGER.info("New customer created : {}", customer);
var hasBorrowerRole = customer.hasRole(BORROWER);
LOGGER.info("Customer has a borrower role - {}", hasBorrowerRole);
var hasInvestorRole = customer.hasRole(INVESTOR);
LOGGER.info("Customer has an investor role - {}", hasInvestorRole);
customer.getRole(INVESTOR, InvestorRole.class)
.ifPresent(inv -> {
inv.setAmountToInvest(1000);
inv.setName("Billy");
});
customer.getRole(BORROWER, BorrowerRole.class)
.ifPresent(inv -> inv.setName("Johny"));
customer.getRole(INVESTOR, InvestorRole.class)
.map(InvestorRole::invest)
.ifPresent(LOGGER::info);
customer.getRole(BORROWER, BorrowerRole.class)
.map(BorrowerRole::borrow)
.ifPresent(LOGGER::info);
}
In this class, a Customer object is created with both Borrower and Investor roles. The hasRole method is used to check if the Customer object has a specific role. The getRole method is used to get a reference to the role object, which is then used to perform role-specific operations.
Running the example outputs:
10:22:02.561 [main] INFO com.iluwatar.roleobject.ApplicationRoleObject -- New customer created : Customer{roles=[INVESTOR, BORROWER]}
10:22:02.564 [main] INFO com.iluwatar.roleobject.ApplicationRoleObject -- Customer has a borrower role - true
10:22:02.564 [main] INFO com.iluwatar.roleobject.ApplicationRoleObject -- Customer has an investor role - true
10:22:02.574 [main] INFO com.iluwatar.roleobject.ApplicationRoleObject -- Investor Billy has invested 1000 dollars
10:22:02.575 [main] INFO com.iluwatar.roleobject.ApplicationRoleObject -- Borrower Johny wants to get some money.
When to Use the Role Object Pattern in Java
- When an object needs to change its behavior dynamically based on its role.
- When multiple objects share common behaviors but should exhibit those behaviors differently based on their roles.
- In scenarios where roles can be added, removed, or changed at runtime.
Real-World Applications of Role Object Pattern in Java
- User role management in applications where users can have different permissions and responsibilities.
- Game character roles where characters can take on different roles (e.g., healer, warrior, mage) dynamically.
- Workflow systems where tasks can be assigned different roles depending on the context.
Benefits and Trade-offs of Role Object Pattern
Benefits:
- Enhances software flexibility by enabling Java objects to dynamically switch roles, catering to evolving application needs.
- Enhances code maintainability by decoupling role-specific behaviors from core object logic.
- Facilitates the addition of new roles without modifying existing code.
Trade-offs:
- Increases complexity due to the need for managing multiple role objects.
- Potential performance overhead due to the dynamic nature of role assignment and behavior switching.
Related Java Design Patterns
- Strategy: Similar in dynamically changing an object's behavior, but Role Object focuses on roles that can be combined.
- Decorator: Both can add behaviors to objects, but Role Object allows for dynamic role switching rather than static enhancement.
- State: Manages state transitions similar to role changes, but Role Object deals more with behavioral roles rather than states.
References and Credits
- Design Patterns: Elements of Reusable Object-Oriented Software
- Pattern-Oriented Software Architecture Volume 1: A System of Patterns
- Role-Based Access Control
- Dealing with Roles (Martin Fowler)
- Role Object (wiki.c2.com)
- The Role Object Pattern (Dirk Bäumer, Dirk Riehle, Wolf Siberski, and Martina Wulf)