Skip to content

Commit d1767bb

Browse files
besokiluwatar
authored andcommitted
The pattern Role object (iluwatar#1031)
* init repo for role object * add to init * add to init * add first impl * add pattern * add license * add changes
1 parent 5d47488 commit d1767bb

File tree

14 files changed

+747
-0
lines changed

14 files changed

+747
-0
lines changed

role-object/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
layout: pattern
3+
title: Role object
4+
folder: Migration
5+
permalink: /patterns/role-object/
6+
categories: Structural
7+
tags:
8+
- Java
9+
- Difficulty-Medium
10+
- Handle Body Pattern
11+
---
12+
13+
## Also known as
14+
Post pattern, Extension Object pattern
15+
16+
## Intent
17+
Adapt an object to different client’s needs through transparently attached role objects, each one representing a role
18+
the object has to play in that client’s context. The object manages its role set dynamically. By representing roles as
19+
individual objects, different contexts are kept separate and system configuration is simplified.
20+
21+
## Applicability
22+
Use the Role Object pattern, if:
23+
- you want to handle a key abstraction in different contexts and you do not want to put the resulting context specific interfaces into the same class interface.
24+
- you want to handle the available roles dynamically so that they can be attached and removed on demand, that is at runtime, rather than fixing them statically at compile-time.
25+
- you want to treat the extensions transparently and need to preserve the logical object identity of the resultingobject conglomerate.
26+
- you want to keep role/client pairs independent from each other so that changes to a role do not affect clients that are not interested in that role.
27+
28+
## Credits
29+
- [Hillside - Role object pattern](https://hillside.net/plop/plop97/Proceedings/riehle.pdf)
30+
- [Role object](http://wiki.c2.com/?RoleObject)
31+
- [Fowler - Dealing with roles](https://martinfowler.com/apsupp/roles.pdf)

role-object/pom.xml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
4+
The MIT License
5+
Copyright © 2014-2019 Ilkka Seppälä
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in
15+
all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
THE SOFTWARE.
24+
25+
-->
26+
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
27+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
28+
<modelVersion>4.0.0</modelVersion>
29+
<parent>
30+
<groupId>com.iluwatar</groupId>
31+
<artifactId>java-design-patterns</artifactId>
32+
<version>1.22.0-SNAPSHOT</version>
33+
</parent>
34+
35+
<artifactId>role-object</artifactId>
36+
<dependencies>
37+
<dependency>
38+
<groupId>junit</groupId>
39+
<artifactId>junit</artifactId>
40+
<scope>test</scope>
41+
</dependency>
42+
</dependencies>
43+
44+
</project>
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* The MIT License
3+
* Copyright © 2014-2019 Ilkka Seppälä
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
package com.iluwatar.roleobject;
24+
25+
import org.slf4j.Logger;
26+
import org.slf4j.LoggerFactory;
27+
28+
import static com.iluwatar.roleobject.Role.*;
29+
30+
/**
31+
* The Role Object pattern suggests to model context-specific views
32+
* of an object as separate role objects which are
33+
* dynamically attached to and removed from the core object.
34+
* We call the resulting composite object structure,
35+
* consisting of the core and its role objects, a subject.
36+
* A subject often plays several roles and the same role is likely to
37+
* be played by different subjects.
38+
* As an example consider two different customers playing the role of borrower and
39+
* investor, respectively. Both roles could as well be played by a single {@link Customer} object.
40+
* The common superclass for customer-specific roles is provided by {@link CustomerRole},
41+
* which also supports the {@link Customer} interface.
42+
* <p>
43+
* The {@link CustomerRole} class is abstract and not meant to be instantiated.
44+
* Concrete subclasses of {@link CustomerRole}, for example {@link BorrowerRole} or {@link InvestorRole},
45+
* define and implement the interface for specific roles. It is only
46+
* these subclasses which are instantiated at runtime.
47+
* The {@link BorrowerRole} class defines the context-specific view of {@link Customer} objects as needed by the loan department.
48+
* It defines additional operations to manage the customer’s
49+
* credits and securities. Similarly, the {@link InvestorRole} class adds operations specific
50+
* to the investment department’s view of customers.
51+
* A client like the loan application may either work with objects of the {@link CustomerRole} class, using the interface class
52+
* {@link Customer}, or with objects of concrete {@link CustomerRole} subclasses. Suppose the loan application knows a particular
53+
* {@link Customer} instance through its {@link Customer} interface. The loan application may want to check whether the {@link Customer}
54+
* object plays the role of Borrower.
55+
* To this end it calls {@link Customer#hasRole(Role)} with a suitable role specification. For the purpose of
56+
* our example, let’s assume we can name roles with enum.
57+
* If the {@link Customer} object can play the role named “Borrower,” the loan application will ask it
58+
* to return a reference to the corresponding object.
59+
* The loan application may now use this reference to call Borrower-specific operations.
60+
*/
61+
public class ApplicationRoleObject {
62+
63+
private static final Logger logger = LoggerFactory.getLogger(Role.class);
64+
65+
public static void main(String[] args) {
66+
Customer customer = Customer.newCustomer(Borrower, Investor);
67+
68+
logger.info(" the new customer created : {}", customer);
69+
70+
boolean hasBorrowerRole = customer.hasRole(Borrower);
71+
logger.info(" customer has a borrowed role - {}", hasBorrowerRole);
72+
boolean hasInvestorRole = customer.hasRole(Investor);
73+
logger.info(" customer has an investor role - {}", hasInvestorRole);
74+
75+
customer.getRole(Investor, InvestorRole.class)
76+
.ifPresent(inv -> {
77+
inv.setAmountToInvest(1000);
78+
inv.setName("Billy");
79+
});
80+
customer.getRole(Borrower, BorrowerRole.class)
81+
.ifPresent(inv -> inv.setName("Johny"));
82+
83+
customer.getRole(Investor, InvestorRole.class)
84+
.map(InvestorRole::invest)
85+
.ifPresent(logger::info);
86+
87+
customer.getRole(Borrower, BorrowerRole.class)
88+
.map(BorrowerRole::borrow)
89+
.ifPresent(logger::info);
90+
}
91+
92+
93+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* The MIT License
3+
* Copyright © 2014-2019 Ilkka Seppälä
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
package com.iluwatar.roleobject;
24+
25+
public class BorrowerRole extends CustomerRole{
26+
private String name;
27+
28+
public String getName() {
29+
return name;
30+
}
31+
32+
public void setName(String name) {
33+
this.name = name;
34+
}
35+
36+
public String borrow(){
37+
return String.format("Borrower %s wants to get some money.",name);
38+
}
39+
40+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* The MIT License
3+
* Copyright © 2014-2019 Ilkka Seppälä
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
package com.iluwatar.roleobject;
24+
25+
import java.util.Optional;
26+
27+
/**
28+
* The main abstraction to work with Customer.
29+
*/
30+
public abstract class Customer {
31+
32+
/**
33+
* Add specific role @see {@link Role}
34+
*
35+
* @param role to add
36+
* @return true if the operation has been successful otherwise false
37+
*/
38+
public abstract boolean addRole(Role role);
39+
40+
/**
41+
* Check specific role @see {@link Role}
42+
*
43+
* @param role to check
44+
* @return true if the role exists otherwise false
45+
*/
46+
47+
public abstract boolean hasRole(Role role);
48+
49+
/**
50+
* Remove specific role @see {@link Role}
51+
*
52+
* @param role to remove
53+
* @return true if the operation has been successful otherwise false
54+
*/
55+
public abstract boolean remRole(Role role);
56+
57+
/**
58+
* Get specific instance associated with this role @see {@link Role}
59+
*
60+
* @param role to get
61+
* @param expectedRole instance class expected to get
62+
* @return optional with value if the instance exists and corresponds expected class
63+
*/
64+
public abstract <T extends Customer> Optional<T> getRole(Role role, Class<T> expectedRole);
65+
66+
67+
public static Customer newCustomer() {
68+
return new CustomerCore();
69+
}
70+
71+
public static Customer newCustomer(Role... role) {
72+
Customer customer = newCustomer();
73+
for (Role r : role) {
74+
customer.addRole(r);
75+
}
76+
return customer;
77+
}
78+
79+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* The MIT License
3+
* Copyright © 2014-2019 Ilkka Seppälä
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
package com.iluwatar.roleobject;
24+
25+
import java.util.*;
26+
27+
/**
28+
* Core class to store different customer roles
29+
*
30+
* @see CustomerRole
31+
* Note: not thread safe
32+
*/
33+
public class CustomerCore extends Customer {
34+
35+
private Map<Role, CustomerRole> roles;
36+
37+
public CustomerCore() {
38+
roles = new HashMap<>();
39+
}
40+
41+
@Override
42+
public boolean addRole(Role role) {
43+
return role
44+
.instance()
45+
.map(inst -> {
46+
roles.put(role, inst);
47+
return true;
48+
})
49+
.orElse(false);
50+
}
51+
52+
@Override
53+
public boolean hasRole(Role role) {
54+
return roles.containsKey(role);
55+
}
56+
57+
@Override
58+
public boolean remRole(Role role) {
59+
return Objects.nonNull(roles.remove(role));
60+
}
61+
62+
@Override
63+
public <T extends Customer> Optional<T> getRole(Role role, Class<T> expectedRole) {
64+
return Optional
65+
.ofNullable(roles.get(role))
66+
.filter(expectedRole::isInstance)
67+
.map(expectedRole::cast);
68+
}
69+
70+
@Override
71+
public String toString() {
72+
String roles = Arrays.toString(this.roles.keySet().toArray());
73+
return "Customer{roles=" + roles + "}";
74+
}
75+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* The MIT License
3+
* Copyright © 2014-2019 Ilkka Seppälä
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
package com.iluwatar.roleobject;
24+
25+
/**
26+
* Key abstraction for segregated roles
27+
*/
28+
public abstract class CustomerRole extends CustomerCore{}

0 commit comments

Comments
 (0)