I'm looking to implement some sort of jQuery-like object in java-8 which, acting as container, can contain one or more objects.
In Jquery you can e.g do: $('.bla').addClass('ble');. It is unknown whether this is applied on one or more objects, yet the method is only one.
I was also very surprised to see that in java-8 you can do CompletableFuture.allOf(CompletableFuture<?>... cfs).join().
No matter how many objects you pass, you will get a single CompletableFuture<Void> and you can call any instance method that will act on all internal objects.
Still, its implementation is definitely too complex for my case.
My base interface looks like this
public interface Response< T extends DataTransferObject< ? > > {
// instance methods
public boolean isSuccess();
public String getMessage();
public default boolean isUndefined() {
return this.equals(ActionResponse.UNDEF);
}
#SuppressWarnings("unchecked")
public default Response< T > mergeWith(final Response< ? super T > response) {
return Response.allOf(this, response);
}
public default boolean isMultiResponse() {
return this instanceof ActionResponse.ActionMultiResponse;
}
/* -------------------------------------------------------------------------------------------------------------- */
// factory methods
#SuppressWarnings("unchecked")
public static < U extends DataTransferObject< ? > > Response< U > allOf(final Response< ? super U >... responses) {
Objects.requireNonNull(responses);
if (responses.length == 0) return ( Response< U > ) ActionResponse.UNDEF;
return new ActionResponse.ActionMultiResponse< U >(responses);
}
public static < U extends DataTransferObject< ? > > Response< U > from(final boolean success, final String message) {
return new ActionResponse<>(success, message);
}
}
The package-protected class looks like this (incomplete):
/* Package-protected implementation for the Response< T > type */
class ActionResponse< T extends DataTransferObject< ? > > implements Response< T > {
static final Response< ? extends DataTransferObject< ? > > UNDEF = new ActionResponse<>();
private final boolean success;
private final String message;
private ActionResponse() {
this.success = false;
this.message = null;
}
ActionResponse(final boolean success, final String message) {
this.success = success;
this.message = message;
}
// getters
static final class ActionMultiResponse< T extends DataTransferObject< ? > > extends ActionResponse< T > {
private final String[] messages;
ActionMultiResponse(final boolean success, final String message) {
super(success, message);
this.messages = null;
}
ActionMultiResponse(final Response< ? super T >... responses) {
/* must check if any of the following is already a MultiActionResponse */
// TODO
this.messages = new String[responses.length];
for (int i = 0; i < responses.length; i++) {
this.messages[i] = responses[i].getMessage();
}
}
#Override
public String getMessage() {
if (this.messages == null) return super.getMessage();
return Arrays.toString(this.messages); // dummy string merger
}
}
}
It's important that classes outside of this package can access only the interface as I want the implementation details to be hidden. Nobody should care on whether a given instance is a single or a multi.
The only way you can build a Response< T > would be via the factory methods provided or the instance method Response::mergeWith. E.g:
Response< SpotDTO > response = Response.from(true, "message");
If was wondering if this is indeed a pattern and if such pattern has a name? If so, what guidelines should I follow?
What is a better way to implement this concept?
For instance, I do not like that the ActionResponse holds a String type for message whereas ActionMultiResponse has String[].
Still I do not want to have only one object with a String array and place if needed only one object inside.
Related
To avoid duplication in the code, is there a way to extract to a separate method of the selected code?
class Builder
{
private final List< UnitIf > unit = new ArrayList<>();
private final List< TimeIf > time = new ArrayList<>();
public Builder withUnit( final UnitIf aUnit )
{
//Extract to method
if( aUnit != null )
{
unit.add( aUnit );
}
return this;
//----------------
}
public Builder withTime( final TimeIf aTime )
{
//Extract to method
if( aTime != null )
{
time.add( aTime );
}
return this;
//----------------
}
}
My goal is to simplify the code by eliminating duplication. But the parts of code use different data types.
Add a method
public <T> Builder addIfNonNull(List<T> dst, T x)
{
if (x != null) {
dst.add(x);
}
return this;
}
and implement withUnit like
public Builder withUnit( final UnitIf aUnit )
{
return addIfNonNull(unit, aUnit);
}
and change withTime the same way.
Non-generic version
If you don't want it to be a generic method, just omit the type parameter T and change the type of x to be Object:
public Builder addIfNonNull(List dst, Object x)
{
if (x != null) {
dst.add(x);
}
return this;
}
Internally, the Java compiler will compile List<T> to just List. I think it is called "type erasure".
I haven't had a lot of practice with patterns and application architecture. In a nutshell, I have to find certain attributes which object features. Some code will better describe task:
IAttribute {
IAttribute analyze(IFunction func);
}
//up to 10 different attributes
ArgumentsAttribute implements Attribute {
Map<String, ArgType> args = new HashMap<>();
IAttribute analyze(IFunction func) {
for (Argument arg : func.getArgs()) {
args.put(arg.getName(), arg.getType());
}
if (!args.isEmpty()) return this;
return null;
}
}
ReturnAttribute implements Attribute {
IAttribute analyze(IFunction func) {
if (func.hasReturn) return this;
return null;
}
}
AttributeAnalyzer {
List<Attributes> analyzeAttributes(IFunction func) {
List<IAttribute> attributes = new ArrayList<IAttribute>();
attributes.add(new ArgumentAttribute());
attributes.add(new ReturnAttribute());
...
for (IAttribute attr : attributes) {
attr = attr.analyze(func);
if (null == attr) attributes.remove(attr);
}
return attributes;
}
}
However, this implementation seems to be a little strange. I don't like the fact that Attribute is sort of holder, but it has to implement method to find itself. In my opinion, the best practice would be an opportunity to overload static methods, but obviously its not possible. In this way, we would separate holder from analyzing logic without adding new abstractions(maybe I am not right).
IAttribute {
static IAttribute analyze();
}
ConcreteAttribute1 {
int x = 0;
static IAttribute analyze() {
...
if (x != 0) return new ConcreteAttribute1();
return null;
}
}
ConcreteAttribute2 {
String s = "";
static IAttribute analyze() {
...
if (!s.equals("")) return new ConcreteAttribute2();
return null;
}
}
AttributeAnalyzer {
List<Attributes> analyzeAttributes() {
List<IAttribute> attributes = new ArrayList<IAttribute>();
attributes.add(ConcreteAttribute1.analyze());
attributes.add(ConcreteAttribute2.analyze());
...
for (IAttribute attr : attributes) {
if (null == attr) attributes.remove(attr);
}
return attributes;
}
}
In addition, I have to filter spoiled Attributes. So, are there any ways of refactoring to make this code looks better?
If you have a distinct analyze function for each concrete attribute, with little or no overlap, then your initial code sample may not be all that bad. However, I would then change the signature of the method to boolean analyze().
If there is more overlap in the way attributes are analyzed then you might consider a single method boolean analyze(IAttribute) inside your AttributeAnalyzer class (or in a dedicated class).
I am using the factory pattern to create objects of different connections in java version "1.7.0_60"
The problem I am facing is that each concrete class will have unique properties for that particular class. As the factory will use polymorpthism when it return the instance of the concrete class, I cannot access the unique properties. i.e. getHostType() is unique only for SqlServerConnection.
The workaround I have done is to declare getHostType() abstract in the super class and implement it in each concrete class. However, I don't really want to do it that way as the more concrete classes I add that have their unique properties the more abstract methods I will have to include in the super class, and then implement them in each concrete class.
I want to keep my factory pattern and the abstract super class. I am just wondering if there is any other way instead of having the abstract methods in the super class? Any design patterns I can include to get around this?
public abstract class Connection {
private int port;
private int ipAddress;
public Connection() {}
public String description() {
return "Generic";
}
/* Implement in every concrete class, even if the concrete type doesn't have that property */
public abstract int getHostType();
}
public class SqlServerConnection extends Connection {
private int sqlHostType;
public SqlServerConnection() {
sqlHostType = 5060;
}
#Override
public String description() {
return "Created a Sql Server connection type";
}
#Override
public int getHostType() {
return sqlHostType;
}
}
public class OracleConnection extends Connection {
public OracleConnection() {}
#Override
public String description() {
return "Created an Oracle connection type";
}
}
final public class ConnectionFactory {
protected String mType;
public ConnectionFactory(String type) {
mType = type;
}
/* Create the connection we want to use */
public Connection createConnection() {
if(mType.equals("Oracle")) {
return new OracleConnection();
}
else if(mType.equals("SQLServer")) {
return new SqlServerConnection();
}
else {
return null;
}
}
}
public class TestConnection {
public static void main(String[] args) {
ConnectionFactory factory = new ConnectionFactory("SQLServer");
Connection conn = factory.createConnection();
conn = factory.createConnection();
System.out.println(conn.description());
/* need to access the getHostType() */
System.out.println(conn.getHostType());
}
}
You should have a look at the visitor pattern. You need to declare an interface ConnectionVisitor and add an method visit for each of your connection class in your hierarchy.
public interface ConnectionVisitor {
public int visit (Connection connection);
public int visit (SqlServerConnection sqlconnection);
public int visit (OracleConnection oracleConnection)
}
Now you need to add an accept method in your base class connection and that accepts a ConnectionVisitor and then calls visit on it. Your new Connection class will look something like
public abstract class Connection {
private int port;
private int ipAddress;
public Connection() {}
public String description() {
return "Generic";
}
public int accept(ConnectionVisitor visitor){
return visitor.visit(this);
}
}
Notice that the accept method does a dual dispatch. It dispatches on the base of the object on which it is called and the parameter that is passed to this method. This is at the heart of visitor pattern.
You can then implement the ConnectionVisitor interface to define any new functionality without changing your base class.
class DemoVisitor implements ConnectionVisitor{
public int visit(Connection connection){
System.out.println("Visiting Connection");
return 1;
}
public int visit(SqlServerConnection sqlServerConnection){
System.out.println("Visiting SqlServerConnection");
return 1;
}
public int visit(OracleConnection oracleConnection){
System.out.println("Visiting Oracle Connection");
return 1;
}
}
In your TestConnection class you can simply create a new connection object and then call accept method on that object passing a visitor object.
public class TestConnection {
public static void main(String[] args) {
ConnectionFactory factory = new ConnectionFactory("SQLServer");
Connection conn = factory.createConnection();
conn = factory.createConnection();
System.out.println(conn.description());
ConnectionVisitor visitor = new DemoVisitor();
System.out.println(conn.accept(visitor));
}
}
So now any child class specific functionality must not reside in connection class hierarchy instead they must be implemented in new visitors.
Note that this pattern is not going to fit as such in your scenario. One of the limitation of this pattern in that the return type for all the methods in visitor interface must be same. This pattern may or may not fit your needs but it is worth looking into your case as such. You will probably need to modify this pattern to fit your needs. And that is what patterns are all about looking into some common solutions and then modifying those solutions to fit into your problem.
Why do you want that? I mean, I use a Factory to hide specific implementation of factorized object, returning a common abstract class (or an interface).
I wonder why you may want to do something like:
ConnectionFactory factory = new ConnectionFactory("SQLServer");
Connection conn = factory.createConnection();
if(conn.getHostType() == 1 ) {
doSomethingLogic();
}
if(conn.getHostType() == 2) {
doSomethingElseLogic();
}
shouldn't all the ifs be inside the factory?
You need to have the getHostType() method in your Connection class for this method to be called polymorphically.
The only other solution is to type cast the object returned by the factory to the one expected which is not at all a good approach. Reason for this is you will have to keep check on the Class type of the returned object whether it is of ORACLE or MySQL etc through if else statements (unnecessary we have ploymorphism to prevent this). If you just define the method in your Connection class you dont need to worry about the getHostType() method, as it will be called from the correct class polymorphically.
In the oracleConnection class you can just add the method getHostType() that returns null object with an error message in the code you wrote.
I don't know how applicable this approach will be to your specific situation, but you could try grouping related, optional, subclass-specific connection behavior into its own interfaces and then let each concrete class implement the interfaces that are appropriate for it.
In your example, both connection classes implement description() so you could create an Interface called Descriptor and have a method on your abstract class called getDescriptor():
public Descriptor getDescriptor() throws HasNoDescriptorException {
if (self instanceof Descriptor) {
return self;
}
throw new HasNoDescriptorException();
}
And then let interface Descriptor provide the description() method.
You'd get a connector's description like this:
String desc = "";
try {
desc = connector.getDescriptor().description();
} catch (HasNoDescriptorException e) {
// connector doesn't have a description() method;
}
If you don't like exceptions you could just return and test for nulls.
For that matter, your code could simply test to see if the connection instance is an instance of the Descriptor interface and if it is then you know you have full access to any of the methods appropriate for a Descriptor.
To continue the example, you could have a TypedHost interface whose implementing connection classes provide a getSqlHost() method.
I'd do it like this:
Remove the getHostTypeCreate method from the abstract class since not all of the connections have this property. Then add a new interface IHostTypeProvider(you might pick a better name though):
public interface IHostTypeProvider {
int getHostType();
}
Now, make some of the sub-classes implement this interface:
public SqlServerConnection extends Connection implements IHostTypeProvider {
....
public int getHostType() {
return 5060;
}
}
When you actually need access to the property, you fist need to check if it's available for this type of connection:
Connection con = ...;
//Check if host type is available
if (connection instanceof IHostTypeProvider) {
System.out.println(((IHostTypeProvider)con).getHostType());
}
Hope that helps.
Sounds like a use case for typesafe heterogeneous container. I'll just post my example, I think it's pretty much explaining itself. If there are any questions left, I'll answer them.
The Pros are that it is easily extensible and it supports multiple types.
import java.util.HashMap;
import java.util.Map;
public abstract class Connection
{
/* typesafe heterogeneous container */
private final Map<Property<?>, Object> properties = new HashMap<Property<?>, Object>();
public Connection(String ip, int port)
{
addProperty(ConnectionProperties.IP_ADDRESS, ip);
addProperty(ConnectionProperties.PORT, port);
}
/**
* Gets property in its respective type.
*
* #param p property
* #return value of property.
*/
public <T> T getProperty(Property<T> p)
{
Object obj = properties.get(p);
if (obj == null)
return null;
Class<T> clazz = p.getClazz();
return clazz.cast(obj);
}
/**
* Checks whether property is available
*
* #param p property to check for
* #return <code>true</code>, if property is available
*/
public boolean hasProperty(Property<?> p)
{
return properties.get(p) != null;
}
/* helper method to add properties */
protected <T> void addProperty(Property<T> p, T value)
{
properties.put(p, value);
}
}
class SqlServerConnection extends Connection
{
public SqlServerConnection(String ip, int port)
{
super(ip, port);
addProperty(ConnectionProperties.DESCRIPTION, "Created a Sql Server connection type");
addProperty(ConnectionProperties.SQL_HOST_TYPE, 5090);
}
}
/* all properties are stored here (...there could be more classes if needed) */
final class ConnectionProperties
{
private ConnectionProperties()
{
// private contructor to prevent instantiation of utility class
}
public static final Property<String> IP_ADDRESS = new Property<String>("IP_ADDRESS", String.class);
public static final Property<Integer> PORT = new Property<Integer>("PORT", Integer.class);
public static final Property<String> DESCRIPTION = new Property<String>("DESCRIPTION", String.class);
public static final Property<Integer> SQL_HOST_TYPE = new Property<Integer>("SQL_HOST_TYPE", Integer.class);
}
/* property class that serves as key for typesafe heterogeneous container */
final class Property<T>
{
/* has to be unique */
private final String name;
private final Class<T> clazz;
public Property(String name, Class<T> clazz)
{
this.name = name;
this.clazz = clazz;
}
public String getName()
{
return name;
}
public Class<T> getClazz()
{
return clazz;
}
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Property<?> other = (Property<?>) obj;
if (name == null)
{
if (other.name != null)
return false;
}
else if (!name.equals(other.name))
return false;
return true;
}
}
You could also define a interface for Property<T> and for Connection, that would have the future benefit of having the possibility to exchange the implementations, but I left it out to spaer some space here.
If the instantion of properties is to complex, there are also other alternatives. For example following
public final class PropertyV2<T>
{
private static final AtomicInteger KEY_SUPPLY = new AtomicInteger();
/* unique key for property distinction */
private final int key;
private final Class<T> clazz;
private PropertyV2(Class<T> clazz)
{
this.key = KEY_SUPPLY.getAndIncrement();
this.clazz = clazz;
}
/* factory method for string properties */
public static PropertyV2<String> string()
{
return new PropertyV2<String>(String.class);
}
/* factory method for integer properties */
public static PropertyV2<Integer> integer()
{
return new PropertyV2<Integer>(Integer.class);
}
public Class<T> getClazz()
{
return clazz;
}
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + key;
return result;
}
#Override
public boolean equals(Object obj)
{
if (obj == null || getClass() != obj.getClass())
return false;
PropertyV2<?> other = (PropertyV2<?>) obj;
if (key != other.key)
return false;
return true;
}
}
class ConnectionPropertiesV2
{
private ConnectionPropertiesV2()
{
// private constructor to prevent instatiation of utiltiy class
}
PropertyV2<String> IP_ADDRESS = PropertyV2.string();
PropertyV2<Integer> PORT = PropertyV2.integer();
}
The problem hereby is, that you lose the name attribute, which can be useful if you want to use the property name at runtime - let's say in an exception.
The more OO approach is to push the implementation details into the child class, rather than expose them in abstract methods (which may not have a well-defined implementation for some children).
For example rather than writing,
System.out.println(conn.description());
/* need to access the getHostType() */
System.out.println(conn.getHostType());
Instead, write
conn.printTo(System.out);
Then provide a printTo method for each child. In this way, you've refactored the code to hide all of the implementation details of the Connection objects and how it prints itself to a stream.
(I was astonished not to be able to find this question already on stackoverflow, which I can only put down to poor googling on my part, by all means point out the duplicate...)
Here is a toy class that returns the reverse of what you put into it. Currently it works on integers, but would require only very minor changes to work for String.
public class Mirror {
int value;
public int get() {
return reverse(value);
}
private int reverse(int value2) {
String valueString = value + "";
String newString = reverse(valueString);
return Integer.parseInt(newString);
}
private String reverse(String valueString) {
String newString = "";
for (char c : valueString.toCharArray()) {
newString = c + newString;
}
return newString;
}
public void set(int value) {
this.value = value;
}
}
What I'd like to do is make the class generic, but only for, say, two or three possible types. So what I want to write is:
public class Mirror<X, where X is one of Integer, String, or MagicValue {
X value
public X get(){
[...]
What's the correct syntax? My Google-fu is failing me... :(
EDIT: it appears there isn't a correct syntax and it can't appear to be done, so my main question is: why? this seems like the sort of thing that people might want to do before they made the class truly generic...
EDIT EDIT: Managed to work out the why with some labmates today, so added the relevant why answer below.
Unfortunately java does not provide such functionality directly. However I can suggest you the following work around:
Create parametrized class Mirror with private constructor and 3 static factory methods that create instance of Mirror with specific parameter:
public class Mirror<T> {
private T value
private Mirror(T value) {
this.value = value;
}
public static Mirror<Integer> integerMirror(Integer value) {
return new Mirror(value);
}
public static Mirror<String> stringMirror(String value) {
return new Mirror(value);
}
public static Mirror<MagicValue> magicMirror(MagicValue value) {
return new Mirror(value);
}
}
EDIT
Obviously you can (and probably should) separate the class Mirror from its creating, e.g. put the factory methods to separate class MirrorFactory. In this case the constructor should become package protected.
If you want to support large yet limited number of classes you can implement only one generic factory method
public static <T> Mirror<T> createMirror(T value) {
checkTypeSupported(value);
return new Mirror(value);
}
Method checkTypeSupported(value); may use some kind of metadatat (e.g. properties, JSON etc file) to get supported types. In this case however you will not enjoy the compile time validation.
Other solution is to require that all supported types extend certain base class or implement interface:
public class Mirror<T extends MyInterface> {}
But this solution seems does not match your requirements since you need Integer, String and MagicValue.
Various ways to do what you need...Here is another option. No getter or setter.
One instance of Mirror for each type to be handled. One reverse() method.
Tweak as necessary. Add error checking/handling.
public class Mirror<T> {
public T reverse(final T value) {
T result = null;
while (true) {
if (value instanceof String) {
System.out.println("Do for String");
result = value;
break;
}
if (value instanceof Integer) {
System.out.println("Do for Integer");
result = value;
break;
}
if (value instanceof JFrame) {
System.out.println("Do for JFrame");
result = value;
break;
}
throw new RuntimeException("ProgramCheck: Missing handler for type " + value.getClass().getSimpleName());
}
return result;
}
Tester:
final Mirror<String> testerString = new Mirror<>();
testerString.reverse("string");
final Mirror<Integer> testerInteger = new Mirror<>();
testerInteger.reverse(41);
testerInteger.reverse(42);
testerInteger.reverse(43);
final Mirror<JFrame> testerJFrame = new Mirror<>();
testerJFrame.reverse(new JFrame());
Results:
Do for String
Do for Integer
Do for Integer
Do for Integer
Do for JFrame
An alternative would be to just accept the fact that you have no control over the type hierarchy of String/Integer and create an interface to give a common type for the classes you do have control over
public int reverse(int value) {
return Integer.valueOf(new StringBuilder(value + "").reverse()
.toString());
}
public String reverse(String value) {
return new StringBuilder(value + "").reverse().toString();
}
public <T extends Reversible> T reverse(T value) {
value.reverse();
return value;
}
public interface Reversible {
public void reverse();
}
And if you only want one instance of the Mirror class...use a generic method.
public class Mirror {
public <T> T reverse(final T value) {
T result = null;
while (true) {
if (value instanceof String) {
System.out.println("Do for String");
result = value;
break;
}
if (value instanceof Integer) {
System.out.println("Do for Integer");
result = value;
break;
}
if (value instanceof JFrame) {
System.out.println("Do for JFrame");
result = value;
break;
}
throw new RuntimeException("ProgramCheck: Missing handler for type " + value.getClass().getSimpleName());
}
return result;
}
tester:
final Mirror tester = new Mirror();
String s = tester.reverse("string");
Integer i41 = tester.reverse(41);
Integer i42 = tester.reverse(42);
Integer i43 = tester.reverse(43);
JFrame j = tester.reverse(new JFrame());
results:
Do for String
Do for Integer
Do for Integer
Do for Integer
Do for JFrame
You can't bound a generic parameter to range of values. You could however restrict it programatically:
public abstract class AbstractMirror<T> {
T value;
protected AbstractMirror(Class<T> clazz) {
if (clazz != Integer.class && clazz != String.class && clazz != MagicValue.class)
throw new IllegalArgumentException();
}
public abstract T get();
protected abstract T reverse(T value);
}
You can use so-called "witness" types to make the compiler do what you want.
public interface Reversible< T > {
public static final class IntReversible implements Reversible< Integer > {}
public static final class StringReversible implements Reversible< String > {}
public static final class MagicReversible implements Reversible< MagicValue > {}
}
public abstract class Mirror< T, R extends Reversible< T > > {
// ...
}
public class IntMirror extends Mirror< Integer, IntReversible > {
// ...
}
However, the reason your example doesn't make any sense is because you gain virtually nothing from using a generic in this context. What possible algorithm will reverse an integer or a string or a MagicValue without resorting to awful run-time type-checking and casting? The code will be all three reverse algorithms, wrapped with a hideous if-ladder.
So here is the why (worked it out at work)
Generics are always from a subclass, although it looks like
Public class Thing<T> {}
will allow any type in there, really what it's saying is that it will allow any subtype of Object. I.e.
Public class Thing<T extends Object> {}
This is effectively working as inheritance, and indeed, the Oracle Website shows us this happening when the syntactic sugar is removed:
In the following example, the generic Node class uses a bounded type
parameter:
public class Node<T extends Comparable<T>> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
public T getData() { return data; }
// ...
}
The Java compiler replaces the bounded type parameter T with the first
bound class, Comparable:
public class Node {
private Comparable data;
private Node next;
public Node(Comparable data, Node next) {
this.data = data;
this.next = next;
}
public Comparable getData() { return data; }
// ...
}
...and so the answer turns out that the reason you can't limit the types in this way is because it effectively turns into multiple Inheritance, which is nasty, and which I'm happy to avoid....
I need to build a process which will validate a record against ~200 validation rules. A record can be one of ~10 types. There is some segmentation from validation rules to record types but there exists a lot of overlap which prevents me from cleanly binning the validation rules.
During my design I'm considering a chain of responsibility pattern for all of the validation rules. Is this a good idea or is there a better design pattern?
Validation is frequently a Composite pattern. When you break it down, you want to seperate the what you want to from the how you want to do it, you get:
If foo is valid
then do something.
Here we have the abstraction is valid -- Caveat: This code was lifted from currrent, similar examples so you may find missing symbology and such. But this is so you get the picture. In addition, the
Result
Object contains messaging about the failure as well as a simple status (true/false).
This allow you the option of just asking "did it pass?" vs. "If it failed, tell me why"
QuickCollection
and
QuickMap
Are convenience classes for taking any class and quickly turning them into those respected types by merely assigning to a delegate. For this example it means your composite validator is already a collection and can be iterated, for example.
You had a secondary problem in your question: "cleanly binding" as in, "Type A" -> rules{a,b,c}" and "Type B" -> rules{c,e,z}"
This is easily managed with a Map. Not entirely a Command pattern but close
Map<Type,Validator> typeValidators = new HashMap<>();
Setup the validator for each type then create a mapping between types. This is really best done as bean config if you're using Java but Definitely use dependency injection
public interface Validator<T>{
public Result validate(T value);
public static interface Result {
public static final Result OK = new Result() {
#Override
public String getMessage() {
return "OK";
}
#Override
public String toString() {
return "OK";
}
#Override
public boolean isOk() {
return true;
}
};
public boolean isOk();
public String getMessage();
}
}
Now some simple implementations to show the point:
public class MinLengthValidator implements Validator<String> {
private final SimpleResult FAILED;
private Integer minLength;
public MinLengthValidator() {
this(8);
}
public MinLengthValidator(Integer minLength) {
this.minLength = minLength;
FAILED = new SimpleResult("Password must be at least "+minLength+" characters",false);
}
#Override
public Result validate(String newPassword) {
return newPassword.length() >= minLength ? Result.OK : FAILED;
}
#Override
public String toString() {
return this.getClass().getSimpleName();
}
}
Here is another we will combine with
public class NotCurrentValidator implements Validator<String> {
#Autowired
#Qualifier("userPasswordEncoder")
private PasswordEncoder encoder;
private static final SimpleResult FAILED = new SimpleResult("Password cannot be your current password",false);
#Override
public Result validate(String newPassword) {
boolean passed = !encoder.matches(newPassword,user.getPassword());
return (passed ? Result.OK : FAILED);
}
#Override
public String toString() {
return this.getClass().getSimpleName();
}
}
Now here is a composite:
public class CompositePasswordRule extends QuickCollection<Validator> implements Validator<String> {
public CompositeValidator(Collection<Validator> rules) {
super.delegate = rules;
}
public CompositeValidator(Validator<?>... rules) {
super.delegate = Arrays.asList(rules);
}
#Override
public CompositeResult validate(String newPassword) {
CompositeResult result = new CompositeResult(super.delegate.size());
for(Validator rule : super.delegate){
Result temp = rule.validate(newPassword);
if(!temp.isOk())
result.put(rule,temp);
}
return result;
}
public static class CompositeResult extends QuickMap<Validator,Result> implements Result {
private Integer appliedCount;
private CompositeResult(Integer appliedCount) {
super.delegate = VdcCollections.delimitedMap(new HashMap<PasswordRule, Result>(), "-->",", ");
this.appliedCount = appliedCount;
}
#Override
public String getMessage() {
return super.delegate.toString();
}
#Override
public String toString() {
return super.delegate.toString();
}
#Override
public boolean isOk() {
boolean isOk = true;
for (Result r : delegate.values()) {
isOk = r.isOk();
if(!isOk)
break;
}
return isOk;
}
public Integer failCount() {
return this.size();
}
public Integer passCount() {
return appliedCount - this.size();
}
}
}
and now a snippet of use:
private Validator<String> pwRule = new CompositeValidator<String>(new MinLengthValidator(),new NotCurrentValidator());
Validator.Result result = pwRule.validate(newPassword);
if(!result.isOk())
throw new PasswordConstraintException("%s", result.getMessage());
user.obsoleteCurrentPassword();
user.setPassword(passwordEncoder.encode(newPassword));
user.setPwExpDate(DateTime.now().plusDays(passwordDaysToLive).toDate());
userDao.updateUser(user);
Chain of responsibility implies that there is an order in which the validations must take place. I would probably use something similar to the Strategy pattern where you have a Set of validation strategies that are applied to a specific type of record. You could then use a factory to examine the record and apply the correct set of validations.