diff --git a/role-object/README.md b/role-object/README.md index 44f992289..3f71341e1 100644 --- a/role-object/README.md +++ b/role-object/README.md @@ -14,9 +14,22 @@ tags: Post pattern, Extension Object pattern ## Intent +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. ## Applicability - -## Real world examples +Use the Role Object pattern, if: +- you want to handle a key abstraction in different contexts and you do not want to put the resulting contextspecific interfaces into the same class interface. +Words: 4895 Page 3 of 11 +- 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. +- you want to treat the extensions transparently and need to preserve the logical object identity of the resulting +object conglomerate. +- 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. ## Credits +- [Hillside - Role object pattern](https://hillside.net/plop/plop97/Proceedings/riehle.pdf) +- [Role object](http://wiki.c2.com/?RoleObject) +- [Fowler - Dealing with roles](https://martinfowler.com/apsupp/roles.pdf) \ No newline at end of file diff --git a/role-object/src/main/java/com/iluwatar/roleobject/ApplicationRoleObject.java b/role-object/src/main/java/com/iluwatar/roleobject/ApplicationRoleObject.java index 89388099f..3dc83e470 100644 --- a/role-object/src/main/java/com/iluwatar/roleobject/ApplicationRoleObject.java +++ b/role-object/src/main/java/com/iluwatar/roleobject/ApplicationRoleObject.java @@ -1,7 +1,60 @@ +/* + * The MIT License + * Copyright © 2014-2019 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.roleobject; +/** + * The Role Object pattern suggests to model context-specific views + * of an object as separate role objects which are + * dynamically attached to and removed from the core object. + * We call the resulting composite object structure, + * consisting of the core and its role objects, a subject. + * A subject often plays several roles and the same role is likely to + * be played by different subjects. + * As an example consider two different customers playing the role of borrower and + * investor, respectively. Both roles could as well be played by a single Customer object. + * The common superclass for customer-specific roles is provided by CustomerRole, + * which also supports the Customer interface. + * The CustomerRole class is abstract and not meant to be instantiated. + * Concrete subclasses of CustomerRole, for example Borrower or Investor, + * define and implement the interface for specific roles. It is only + * these subclasses which are instantiated at runtime. + * The Borrower class defines the context-specific view of + * Customer objects as needed by the loan department. + * It defines additional operations to manage the customer’s + * credits and securities. Similarly, the Investor class adds operations specific + * to the investment department’s view of customers. + * A client like the loan application may either work with objects of the CustomerCore class, using the interface class + * Customer, or with objects of concrete CustomerRole subclasses. Suppose the loan application knows a particular + * Customer instance through its Customer interface. The loan application may want to check whether the Customer + * object plays the role of Borrower. + * To this end it calls hasRole() with a suitable role specification. For the purpose of + * our example, let’s assume we can name roles with a simple string. + * If the Customer object can play the role named + * “Borrower,” the loan application will ask it to return a reference to the corresponding object. + * The loan application may now use this reference to call Borrower-specific operations. + * + */ public class ApplicationRoleObject { public static void main(String[] args) { - System.out.println("Role-object"); } } diff --git a/role-object/src/main/java/com/iluwatar/roleobject/BorrowerRole.java b/role-object/src/main/java/com/iluwatar/roleobject/BorrowerRole.java new file mode 100644 index 000000000..c900e3eed --- /dev/null +++ b/role-object/src/main/java/com/iluwatar/roleobject/BorrowerRole.java @@ -0,0 +1,4 @@ +package com.iluwatar.roleobject; + +public class BorrowerRole extends CustomerRole{ +} diff --git a/role-object/src/main/java/com/iluwatar/roleobject/Customer.java b/role-object/src/main/java/com/iluwatar/roleobject/Customer.java new file mode 100644 index 000000000..c9cdab4e1 --- /dev/null +++ b/role-object/src/main/java/com/iluwatar/roleobject/Customer.java @@ -0,0 +1,12 @@ +package com.iluwatar.roleobject; + +import java.util.Optional; + +public abstract class Customer { + + public abstract boolean addRole(Role role); + public abstract boolean hasRole(Role role); + public abstract boolean remRole(Role role); + public abstract Optional getRole(Role role,Class expectedRole); + +} diff --git a/role-object/src/main/java/com/iluwatar/roleobject/CustomerCore.java b/role-object/src/main/java/com/iluwatar/roleobject/CustomerCore.java new file mode 100644 index 000000000..496022c06 --- /dev/null +++ b/role-object/src/main/java/com/iluwatar/roleobject/CustomerCore.java @@ -0,0 +1,35 @@ +package com.iluwatar.roleobject; + +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +public class CustomerCore extends Customer { + + private Map roles; + + + @Override + public boolean addRole(Role role) { + return role.instance() + .map(rI -> roles.put(role, rI)) + .isPresent(); + } + + @Override + public boolean hasRole(Role role) { + return roles.containsKey(role); + } + + @Override + public boolean remRole(Role role) { + return Objects.nonNull(roles.remove(role)); + } + + @Override + public Optional getRole(Role role, Class expectedRole) { + return Optional.ofNullable(roles.get(role)) + .filter(expectedRole::isInstance) + .map(expectedRole::cast); + } +} diff --git a/role-object/src/main/java/com/iluwatar/roleobject/CustomerRole.java b/role-object/src/main/java/com/iluwatar/roleobject/CustomerRole.java new file mode 100644 index 000000000..af2801f3d --- /dev/null +++ b/role-object/src/main/java/com/iluwatar/roleobject/CustomerRole.java @@ -0,0 +1,25 @@ +package com.iluwatar.roleobject; + +import java.util.Optional; + +public class CustomerRole extends Customer{ + @Override + public boolean addRole(Role role) { + return false; + } + + @Override + public boolean hasRole(Role role) { + return false; + } + + @Override + public boolean remRole(Role role) { + return false; + } + + @Override + public Optional getRole(Role role, Class expectedRole) { + return Optional.empty(); + } +} diff --git a/role-object/src/main/java/com/iluwatar/roleobject/InvestorRole.java b/role-object/src/main/java/com/iluwatar/roleobject/InvestorRole.java new file mode 100644 index 000000000..a8a85d9da --- /dev/null +++ b/role-object/src/main/java/com/iluwatar/roleobject/InvestorRole.java @@ -0,0 +1,4 @@ +package com.iluwatar.roleobject; + +public class InvestorRole extends CustomerRole{ +} diff --git a/role-object/src/main/java/com/iluwatar/roleobject/Role.java b/role-object/src/main/java/com/iluwatar/roleobject/Role.java new file mode 100644 index 000000000..a59d6377b --- /dev/null +++ b/role-object/src/main/java/com/iluwatar/roleobject/Role.java @@ -0,0 +1,30 @@ +package com.iluwatar.roleobject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sun.rmi.runtime.Log; + +import java.util.Optional; + +public enum Role { + Borrower(BorrowerRole.class), Investor(InvestorRole.class); + + private Class typeCst; + + Role(Class typeCst) { + this.typeCst = typeCst; + } + private static final Logger logger = LoggerFactory.getLogger(Role.class); + + @SuppressWarnings("unchecked") + Optional instance(){ + Class typeCst = this.typeCst; + try { + return (Optional) Optional.of(typeCst.newInstance()); + } catch (InstantiationException | IllegalAccessException e) { + logger.error("error creating an object",e); + } + return Optional.empty(); + } + +}