Design Pattern for dealing with a complex conditional evaluation - java

I am designed to maintain a system that takes in account the value of three variables to determine which action it will take.
I want to refactor it to use a design pattern, but could not find one suitable for it needs.
To explain the situation, I will use as an example a gym system.
Every gym user has a TYPE_OF_CONTRACT, that could be:
PLATINUM_MEMBERSHIP
GOLD_MEMBERSHIP
SILVER_MEMBERSHIP
The gym has some GYM_CLASSES:
WEIGHT_LIFTING
BODY_BALANCE
STEP
SPINNING
ZUMBA
PERSONAL_TRAINING
Every gym user has a PHYSICAL_CONDITION
NO_RESTRICTIONS
OVER_65
LIMITED_MOBILITY
MEDICAL_CONDITION
BELOW_18
For each combination of these three characteristics, a arbitrary set of actions should be executed. For example:
if PLATINUM_MEMBERSHIP + PERSONAL_TRAINING + OVER_65:
medical approval needed
signed form
if GOLD_MEMBERSHIP + PERSONAL_TRAINING + OVER_65:
medical approval needed
signed form
extra monthly fee
if SILVER_MEMBERSHIP + PERSONAL_TRAINING + OVER_65:
refuse subscription
if (any membership) + STEP + MEDICAL_CONDITION:
medical approval needed
signed form
if PLATINUM_MEMBERSHIP + WEIGHT_LIFTING + LIMITED_MOBILITY:
medical approval needed
signed form
dedicated staff member assist
And so on.
The combination of characteristics can have a set of actions, that are not exclusive and not all of the combinations are ensured.
The legacy code uses nested switches as implementation. Example:
switch (contractType):
case PLATINUM_MEMBERSHIP:
switch (gymClass):
case (PERSONAL_TRAINING):
switch (physicalCondition):
case (OVER_65):
requiresMedicalApproval();
requiresSignedForm();
...
My problem is:
there are 3 conditions that combines to define a set of rules;
these rules are not necessarily unique;
not every combination defines a set;
I refactored a little using extract method technique and cleaning the code a little, but could not get rid of the 3 switches.
I wish to use design patterns to improve the design but so far I was unsuccessful.
I thought about polymorphism and Strategy, but could not figure a way to use any of them.
I also researched in google but haven't found anything that I could use.
What do you suggest?
Thank you.
EDIT:
A solution I reached, while researching #Paul's decision tree approach. After testing with a decision tree, I tried a three dimensional array, to define the conditions of the rules. I also used the Command pattern to define the actions that needed to be performed if the rule is activated.
In brief:
1) Enums to define the variables:
public enum TypeOfContract { ... }
public enum GymClasses { ... }
public enum PhysicalCondition { ... }
Every possible condition would be put in the enums.
2) The Command interface to define the actions
public interface Command {
public void execute(Map<String, Object> parametersMap);
}
Every action would be an implementation of Command. The Map parameter will be used to pass runtime context to the methods.
3) A Procedures class to hold the actions needed for each condition.
public class Procedures {
private List<Command> actionsToExecute = new LinkedList<Command>();
public static final Procedures NO_ACTIONS_TO_EXECUTE = new Procedures();
private Procedures() {}
public Procedures(Command... commandsToExecute) {
if (commandsToExecute == null || commandsToExecute.length == 0) {
throw new IllegalArgumentException("Procedures must have at least a command for execution.");
}
for (Command command : commandsToExecute) {
actionsToExecute.add(command);
}
}
public List<Command> getActionsToExecute() {
return Collections.unmodifiableList(this.actionsToExecute);
}
}
The Procedures class represent the Commands that needed to be executed. It has a LinkedList of Command, to ensure that the Commands are executed in the desired order.
It has the NO_ACTIONS_TO_EXECUTE to be sent instead of a null, in case a combination of the three variables does not exist.
4) A RulesEngine class, to register the rules and its commands
public class RulesEngine {
private static final int NUMBER_OF_FIRST_LEVEL_RULES = TypeOfContract.values().length;
private static final int NUMBER_OF_SECOND_LEVEL_RULES = GymClasses.values().length;
private static final int NUMBER_OF_THIRD_LEVEL_RULES = PhysicalCondition.values().length;
private static final Procedures[][][] RULES =
new Procedures[NUMBER_OF_FIRST_LEVEL_RULES]
[NUMBER_OF_SECOND_LEVEL_RULES]
[NUMBER_OF_THIRD_LEVEL_RULES];
{ //static block
RULES
[TypeOfContract.PLATINUM_MEMBERSHIP.ordinal()]
[GymClasses.PERSONAL_TRAINING.ordinal()]
[PhysicalCondition.OVER_65.ordinal()] =
new Procedures(new RequireMedicalApproval(),
new RequireSignedForm() );
RULES
[TypeOfContract.GOLD_MEMBERSHIP.ordinal()]
[GymClasses.PERSONAL_TRAINING.ordinal()]
[PhysicalCondition.OVER_65.ordinal()] =
new Procedures(new RequireMedicalApproval(),
new RequireSignedForm(),
new AddExtraMonthlyFee() );
...
}
private RulesEngine() {}
public static Procedures loadProcedures(TypeOfContract TypeOfContract,
GymClasses GymClasses, PhysicalCondition PhysicalCondition) {
Procedures procedures = RULES
[TypeOfContract.ordinal()]
[GymClasses.ordinal()]
[PhysicalCondition.ordinal()];
if (procedures == null) {
return Procedures.NO_ACTIONS_TO_EXECUTE;
}
return procedures;
}
}
(Unusual code formatting done for the sake of visualization in this site)
Here the meaningful associations of variables are defined in the RULES three dimensional array.
The rules are defined by employing the corresponding enums.
For the first example I gave, PLATINUM_MEMBERSHIP + PERSONAL_TRAINING + OVER_65, the following would apply:
RULES
[TypeOfContract.PLATINUM_MEMBERSHIP.ordinal()]
[GymClasses.PERSONAL_TRAINING.ordinal()]
[PhysicalCondition.OVER_65.ordinal()]
(the ordinal() is needed to return the int corresponding to the position of the enum)
To represent the actions needed to perform, a Procedures class is associated, wrapping the actions that are to be executed:
new Procedures(new RequireMedicalApproval(), new RequireSignedForm() );
Both RequireMedicalApproval and RequireSignedForm implement the Command interface.
The whole line for defining this combination of variables would be:
RULES
[TypeOfContract.PLATINUM_MEMBERSHIP.ordinal()]
[GymClasses.PERSONAL_TRAINING.ordinal()]
[PhysicalCondition.OVER_65.ordinal()] =
new Procedures(new RequireMedicalApproval(),
new RequireSignedForm() );
To check if a particular combination has actions associated to them, the loadProcedures is called, passing the enums representing that particular combination.
5) Usage
Map<String, Object> context = new HashMap<String, Object>();
context.put("userId", 123);
context.put("contractId", "C45354");
context.put("userDetails", userDetails);
context.put("typeOfContract", TypeOfContract.PLATINUM_MEMBERSHIP);
context.put("GymClasses", GymClasses.PERSONAL_TRAINING);
context.put("PhysicalCondition", PhysicalCondition.OVER_65);
...
Procedures loadedProcedures = RulesEngine.loadProcedures(
TypeOfContract.PLATINUM_MEMBERSHIP,
GymClasses.PERSONAL_TRAINING,
PhysicalCondition.OVER_65);
for (Command action : loadedProcedures.getActionsToExecute()) {
action.equals(context);
}
All information the actions need to execute are now inside a Map.
The conditions, represented by the three enums, are passed to the RulesEngine.
The RulesEngine will evaluate if the combination has associated actions and it will return a Procedures object with the list of these actions that needs to be executed.
If not (the combination has no action associated to it), the RulesEngine will return a valid Procedures object with an empty list.
6) Pros
The usage code is much cleaner
The duplication of code in the switches of the legacy code are now gone
The actions are now standardized and well defined (each one in its own class)
The rules used are now much easier to discern (a developer just needs to look at the RULES array to know which rules are set and what will happen in each one of them)
New rules and actions can be easily added
7) Cons
Easy to make mistakes in the definition of the rules, as the declaration of them is verbose and not semantically analysed - it will accepted repetitions, for example, possibly overwriting previous definitions.
Instead of 3 switches nested inside each other, now I have several classes. The maintenance of the system is a little more complex than before, the learning curve a little steeper.
procedures and rules are not good names - still looking for better ones ;-)
Map as parameter can promote bad coding, cluttering it with a lot of content.

How many options will you have? Let's say you have 8 per category, perhaps you can represent a particular combination as a 24-bit number, with 8 bits per category. When you receive a set of options, convert it over to a bit-pattern than then AND against bit-masks to figure out if a certain action needs to be done.
This still requires you to perform tests, but at least they are not nested, and you simply need to add a new test if/when you add a new feature.

You could use a decision-tree and build it from tuples of values.
This would be a lot simpler and if properly implemented even faster than hard-coded conditions and in addition provides higher maintainability.

In terms of design patterns, if you would like to decrease the complexity, you can use the abstract factory.
You can create three hierarchy of classes.
TYPE_OF_CONTRACT (AbstractProductA)
PLATINUM_MEMBERSHIP (ProductA1)
GOLD_MEMBERSHIP (ProductA2)
SILVER_MEMBERSHIP (ProductA3)
GYM_CLASSES (AbstractProductB)
WEIGHT_LIFTING (ProductB1)
BODY_BALANCE (ProductB2)
STEP (ProductB3)
SPINNING (ProductB4)
ZUMBA (ProductB5)
PERSONAL_TRAINING (ProductB6)
PHYSICAL_CONDITION (AbstractProductC)
NO_RESTRICTIONS (ProductC1)
OVER_65 (ProductC2)
LIMITED_MOBILITY (ProductC3)
MEDICAL_CONDITION (ProductC4)
BELOW_18 (ProductC5)

Related

Identification of a service

Service interface:
public interface UserInterface {
void present();
void onStart();
void onStop();
}
I have two implementations: TextUserInterface and GraphicalUserInterface.
How can I identify the one I want to use when I launch my program? Source
private static void main(String[] args) {
ServiceLoader<UserInterface> uiLoader = ServiceLoader.load(UserInterface.class);
UserInterface ui = uiLoader.? //what to do to identify the one I want to use?
}
I was thinking of introducing an enum with the type of UI, so I could just iterate through all services and pick the one I'd like to, but isn't this approach just a misuse of services? In this case when I want to pick GraphicalUserInterface I could just skip the ServiceLoader part and just instantiate one. The only difference I see is fact that without services, I'd have to require the GraphicalUserInterface module, which "kind of" breaks the encapsulation.
I don't actually think that it would be a misuse of it. As a matter of fact, what you get from ServiceLoader.load(...) method is an Iteratable object, and if you need for a specific service, you will have to iterate through all the available instances.
The idea of the enum is not that bad, but I suggest that you take advantage of the Java stream and filter for the instance you need. For example, you might have something like that:
enum UserInterfaceType {
TEXT_UI, GRAPH_UI;
}
public interface UserInterface {
UserInterfaceType getTypeUI();
...
}
// In your main method
ServiceLoader<UserInterface> uiLoader = ServiceLoader.load(UserInterface.class);
UserInterface ui = uiLoader.steam()
.filter(p -> p->getTypeUI() == <TypeUIyouNeed> )
.findFirst()
.get();
That is open to a number of possibilities, for example you can put this is a separated method, which receives in input a UserInterfaceType value, and it can retrieve the service implementation based on the type enum value you passed.
As I said, that is just the main idea, but definitely you are not doing any misuse of the ServiceLoader.

Import classes in method?

I'm customizing a PLM Windchill Workflow, which provides a mechanism to execute java code snippets. Unfortunately, they are 'inserted' into prepared service's method, which means that there is no way to import classes, so I have to include full package names to use it. Don't try to understand the snippet below, just look how does it looks like:
wt.fc.QueryResult activities = wt.fc.PersistenceHelper.manager.find((wt.pds.StatementSpec) activitiesQuery);
while (activities.hasMoreElements()) {
wt.workflow.work.WfAssignedActivity activity = (wt.workflow.work.WfAssignedActivity) activities.nextElement();
if(activity.getDisplayIdentifier().toString().equals("Analyze Image Request")){
java.util.List<wt.workflow.work.WorkItem> workItems = wt.workflow.status.WfWorkflowStatusHelper.service.getWorkItems(activity);
for (wt.workflow.work.WorkItem workItem : workItems){
String action = workItem.getActionPerformed();
if(action != null && action.equals("Accepted")){
wt.org.WTPrincipalReference approver = workItem.getOwnership().getOwner();
n_approver = approver.getFullName() + " ("+approver.getDisplayName()+")";
wt.fc.collections.WTHashSet approverSet = new wt.fc.collections.WTHashSet(java.util.Arrays.asList(approver));
wt.project.Role role = wt.project.Role.toRole("APPROVER");
com.ptc.windchill.pdmlink.change.server.impl.WorkflowProcessHelper.setChangeItemParticipants(report, role, approverSet);
break;
}
}
break;
}
}
And my question is - how to make this code any more readable? Of course there is no way to import classes inside the method, there is even no way to divide this snippet into separate methods (as it is 'pasted' into one) so I'm looking for other ideas.
One option to make the code more readable would be to separate chained method/property calls across multiple lines.
For example, this line:
wt.project.Role role = wt.project.Role.toRole("APPROVER");
could be rewritten as:
wt.project.Role role = wt
.project
.Role
.toRole("APPROVER");
You can call this complete code from a Customized Java class.
You just have to call your class and take the final parameters required from the Java class to make it more readable.
If you need multiple outputs write multiple methods in Java class and call them in workflow expression.
You can't.
Workflows expressions are methods bodies.
A statement like
wt.fc.QueryResult activities = wt.fc.PersistenceHelper.manager.find((wt.pds.StatementSpec) activitiesQuery);
ends in a class under $WT_HOME/codebase/wt/workflow/expr/
with a method :
public static Object executemethod_1(Object[] var0, Object[] var1) throws Exception {
wt.fc.QueryResult activities = wt.fc.PersistenceHelper.manager.find((wt.pds.StatementSpec) activitiesQuery);
// some generated code to handle variables...
}
So, you can't use import.
However :
If you have a PDMLink version greater than 10,
You can externalize workflow expression
http://support.ptc.com/cs/help/windchill_hc/wc100_hc/index.jspx?id=WFTemplateExtExpression&action=show
This create a java class under /codebase/ext/wt/workflow/externalize
Then you can do what you want, but you'll have to compile these classes, and do a stop/start in case of modifications.
Basically, it's nothing more than calling external code from the expression, so I don't use it a lot...

Best practice to associate message and target class instance creation

The program I am working on has a distributed architecture, more precisely the Broker-Agent Pattern. The broker will send messages to its corresponding agent in order to tell the agent to execute a task. Each message sent contains the target task information(the task name, configuration properties needed for the task to perform etc.). In my code, each task in the agent side is implemente in a seperate class. Like :
public class Task1 {}
public class Task2 {}
public class Task3 {}
...
Messages are in JSON format like:
{
"taskName": "Task1", // put the class name here
"config": {
}
}
So what I need is to associate the message sent from the broker with the right task in the agent side.
I know one way is to put the target task class name in the message so that the agent is able to create an instance of that task class by the task name extracted from the message using reflections, like:
Class.forName(className).getConstructor(String.class).newInstance(arg);
I want to know what is the best practice to implement this association. The number of tasks is growing and I think to write string is easy to make mistakes and not easy to maintain.
If you're that specific about classnames you could even think about serializing task objects and sending them directly. That's probably simpler than your reflection approach (though even tighter coupled).
But usually you don't want that kind of coupling between Broker and Agent. A broker needs to know which task types there are and how to describe the task in a way that everybody understands (like in JSON). It doesn't / shouldn't know how the Agent implements the task. Or even in which language the Agent is written. (That doesn't mean that it's a bad idea to define task names in a place that is common to both code bases)
So you're left with finding a good way to construct objects (or call methods) inside your agent based on some string. And the common solution for that is some form of factory pattern like: http://alvinalexander.com/java/java-factory-pattern-example - also helpful: a Map<String, Factory> like
interface Task {
void doSomething();
}
interface Factory {
Task makeTask(String taskDescription);
}
Map<String, Factory> taskMap = new HashMap<>();
void init() {
taskMap.put("sayHello", new Factory() {
#Override
public Task makeTask(String taskDescription) {
return new Task() {
#Override
public void doSomething() {
System.out.println("Hello" + taskDescription);
}
};
}
});
}
void onTask(String taskName, String taskDescription) {
Factory factory = taskMap.get(taskName);
if (factory == null) {
System.out.println("Unknown task: " + taskName);
}
Task task = factory.makeTask(taskDescription);
// execute task somewhere
new Thread(task::doSomething).start();
}
http://ideone.com/We5FZk
And if you want it fancy consider annotation based reflection magic. Depends on how many task classes there are. The more the more effort to put into an automagic solution that hides the complexity from you.
For example above Map could be filled automatically by adding some class path scanning for classes of the right type with some annotation that holds the string(s). Or you could let some DI framework inject all the things that need to go into the map. DI in larger projects usually solves those kinds of issues really well: https://softwareengineering.stackexchange.com/questions/188030/how-to-use-dependency-injection-in-conjunction-with-the-factory-pattern
And besides writing your own distribution system you can probably use existing ones. (And reuse rather then reinvent is a best practice). Maybe http://www.typesafe.com/activator/template/akka-distributed-workers or more general http://twitter.github.io/finagle/ work in your context. But there are way too many other open source distributed things that cover different aspects to name all the interesting ones.

Decoration pattern used for creating JMSMessages / Where should the timeout start

I started to build a messaging framework and I decided to use the decoration pattern for creating JMSMessages.
class BaseMessage implements Message { ... }
Abstract decoration
class AbstractDecoration implements Message {
Message message;
public AbstractDecoration(Message message) {
this.message = message
}
}
Decoration example:
class JsonPayloadDecoration extends AbstractDecoration { ... }
Usage example:
...
IMessage m = new BaseMessage(...);
m = new ExpireDecoration(m, 10, TimeUnit.MINUTES);
m = new TextPayloadDecoration(m, "Text!");
m = new CorrelationDecoration(m, "123456");
m = new PriorityDecoration(m, 9);
m = new NonPersistentDecoration(m);
m = new QueueDestinationDecoration(m, "JMSTEST.DECORATIONTEST1");
m = new ErrorHandlerDecoration(m, errorhandler, 1000);
// requestor handles MessageProducers
// m.send will create the real JMSMessage and use the requestor
// to send the message with a MessageProducer
m.send(requestor);
At first I would like to get some input about the whole decoration idea and now to my real question. The errorhandler of ErrorHandlerDecoration has a timeout. When should the timeout start? When it's created or when m.send is called? I am arguing with my colleagues about that.
Isn't a "timeout" triggered when a message takes too long to send? It should probably start when send is called, unless the constructor is doing something special other than populating fields.
Regarding your question about the wisdom of using dectorator pattern: decorator pattern is great for offering permutations of features, which seems to be your case (however, this usage is not present in your code sample). If you're only ever going to apply one decorator to the Message, consider using the Strategy Pattern instead.
Also be careful of mutually exclusive decorators. If you have too many of these, it might just be confusing to keep track of which decorators are compatible with which.
Edit in response to your comment: One way to ensure incompatible decorators aren't being used together is get the list of decorators applied to the object so far and throw an exception when you see a conflict. To get the list of decorators, maybe add this method to AbstractDecoration:
List<AbstractDecoration> getDecorations() {
List<AbstractDecoration> decorations;
if (message instanceof AbstractDecoration) {
decorations = ((AbstractDecoration) message).getDecorations();
}
else {
decorations = new ArrayList<AbstractDecoration>();
}
decorations.add(this);
return decorations;
}
So once you have the list of decorators already applied, just simply check instanceof on each one to detect a conflict. Note that you'll have to do this on both ends of the mutually exclusive decorators in question or else this validation won't happen when the decorators are applied in one order versus the other.
Slightly feels like a hack. I'm no pro on Decorator pattern, so I have no idea what the standard is for solving this problem; I came up with this on the spot.
Edit: After thinking about this some more, it might make more sense to do this validation in the constructor of AbstractDecoration. Then, your rules are centralized and you can even delegate them to another class.

Good practice to validate immutable values objects

Suppose a MailConfiguration class specifying settings for sending mails :
public class MailConfiguration {
private AddressesPart addressesPart;
private String subject;
private FilesAttachments filesAttachments;
private String bodyPart;
public MailConfiguration(AddressesPart addressesPart, String subject, FilesAttachments filesAttachements,
String bodyPart) {
Validate.notNull(addressesPart, "addressesPart must not be null");
Validate.notNull(subject, "subject must not be null");
Validate.notNull(filesAttachments, "filesAttachments must not be null");
Validate.notNull(bodyPart, "bodyPart must not be null");
this.addressesPart = addressesPart;
this.subject = subject;
this.filesAttachements = filesAttachements;
this.bodyPart = bodyPart;
}
// ... some useful getters ......
}
So, I'm using two values objects : AddressesPart and FilesAttachment.
Theses two values objects have similar structures so I'm only going to expose here AddressesPart :
public class AddressesPart {
private final String senderAddress;
private final Set recipientToMailAddresses;
private final Set recipientCCMailAdresses;
public AddressesPart(String senderAddress, Set recipientToMailAddresses, Set recipientCCMailAdresses) {
validate(senderAddress, recipientToMailAddresses, recipientCCMailAdresses);
this.senderAddress = senderAddress;
this.recipientToMailAddresses = recipientToMailAddresses;
this.recipientCCMailAdresses = recipientCCMailAdresses;
}
private void validate(String senderAddress, Set recipientToMailAddresses, Set recipientCCMailAdresses) {
AddressValidator addressValidator = new AddressValidator();
addressValidator.validate(senderAddress);
addressValidator.validate(recipientToMailAddresses);
addressValidator.validate(recipientCCMailAdresses);
}
public String getSenderAddress() {
return senderAddress;
}
public Set getRecipientToMailAddresses() {
return recipientToMailAddresses;
}
public Set getRecipientCCMailAdresses() {
return recipientCCMailAdresses;
}
}
And the associated validator : AddressValidator
public class AddressValidator {
private static final String EMAIL_PATTERN
= "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*#[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
public void validate(String address) {
validate(Collections.singleton(address));
}
public void validate(Set addresses) {
Validate.notNull(addresses, "List of mail addresses must not be null");
for (Iterator it = addresses.iterator(); it.hasNext(); ) {
String address = (String) it.next();
Validate.isTrue(address != null && isAddressWellFormed(address), "Invalid Mail address " + address);
}
}
private boolean isAddressWellFormed(String address) {
Pattern emailPattern = Pattern.compile(EMAIL_PATTERN);
Matcher matcher = emailPattern.matcher(address);
return matcher.matches();
}
}
Thus, I have two questions :
1) If for some reasons, later, we want to validate differently an address mail (for instance to include/exclude some aliases matching to existing mailingList), should I expose a kind of IValidator as a constructor parameter ? like the following rather than bringing concrete dependence (like I made):
public AddressValidator(IValidator myValidator) {
this.validator = myValidator;
}
Indeed, this will respect the D principle of SOLID principle : Dependency injection.
However, if we follow this logical, would a majority of Values Objects own an abstract validator or it's just an overkill the most of time (thinking to YAGNI ?) ?
2) I've read in some articles than in respect of DDD, all validations must be present and only present in Aggregate Root, means in this case : MailConfiguration.
Am I right if I consider that immutable objects should never be in an uncohesive state ? Thus, would validation in constructor as I made be preferred in the concerned entity (and so avoiding aggregate to worry about validation of it's "children" ?
There's a basic pattern in DDD that perfectly does the job of checking and assembling objects to create a new one : the Factory.
I've read in some articles than in respect of DDD, all validations
must be present and only present in Aggregate Root
I strongly disagree with that. There can be validation logic in a wide range of places in DDD :
Validation upon creation, performed by a Factory
Enforcement of an aggregate's invariants, usually done in the Aggregate Root
Validation spanning accross several objects can be found in Domain Services.
etc.
Also, I find it funny that you bothered to create an AddressesPart value object -which is a good thing, without considering making EMailAddress a value object in the first place. I think it complicates your code quite a bit because there's no encapsulated notion of what an email address is, so AddressesPart (and any object that will manipulate addresses for that matter) is forced to deal with the AddressValidator to perform validation of its addresses. I think it shouldn't be its responsibility but that of an AddressFactory.
I'm not quite sure if I follow you 100%, but one way to handle ensuring immutable objects are only allowed to be created if they are valid is to use the Essence Pattern.
In a nutshell, the idea is that the parent class contains a static factory that creates immutable instances of itself based on instances of an inner "essence" class. The inner essence is mutable and allows objects to be built up, so you can put the pieces together as you go, and can be validated along the way as well.
The SOLID principals and good DDD is abided by since the parent immutable class is still doing only one thing, but allows others to build it up through it's "essence".
For an example of this, check out the Ldap extension to the Spring Security library.
Some observations first.
Why no generics? J2SE5.0 came out in 2004.
Current version of Java SE has Objects.requiresNonNull as standard. Bit of a mouthful and the capitalisation is wrong. Also returns the passed object so doesn't need a separate line.
this.senderAddress = requiresNonNull(senderAddress);
Your classes are not quite immutable. They are subclassable. Also they don't make a safe copy of their mutable arguments (Sets - shame there aren't immutable collection types in the Java library yet). Note, copy before validation.
this.recipientToMailAddresses = validate(new HashSet<String>(
recipientToMailAddresses
));
The use of ^ and $ in the regex is a little misleading.
If the validation varies, then there's two obvious (sane) choices:
Only do the widest variation in this class. Validate more specifically in the context it is going to be used.
Pass in the validator used and have this as a property. To be useful, client code would have to check and do something reasonable with this information, which is unlikely.
It doesn't make a lot of sense to pass the validator into the constructor and then discard it. That's making the constructor overcomplicated. Put it in a static method, if you must.
The enclosing instance should check that its argument are valid for that particular use, but should not overlap with classes ensuring that they are generally valid. Where would it end?
Although an old question but for anyone stumbling upon the subject matter, please keep it simple with POJOs (Plain Old Java Objects).
As for validations, there is no single truth because for a pure DDD you need to keep the context always in mind.
For example a user with no credit card data can and should be allowed to create an account. But credit card data is needed when checking out on some shopping basket page.
How this is beautifully solved by DDD is by moving the bits and pieces of code to the Entities and Value Objects where it naturally belong.
As a second example, if address should never be empty in the context of a domain level task, then Address value object should force this assertion inside the object instead of using asking a third party library to check if a certain value object is null or not.
Moreover Address as a standalone value object doesn't convey much at its own when compared with ShippingAddress, HomeAddress or CurrentResidentialAddress ... the ubiquitous language, in other words names convey their intent.

Categories

Resources