Question

Is there a design pattern that would allow a class from a hierarchy to 'subscribe to' concrete methods?

For example, say you have an abstract base class that requires the implementation of a method.

Public MustInherit Class Rule
    ' Common properties shared between sub classes
    Public MustOverride Function Validate() As Boolean
End Class

But lets say that the sub classes only want to register to a set of concrete methods for validating themselves.

Lets say a subclass of Rule - RuleItemA Requires the following:

  • The entity must exist
  • The entity must be a number
  • The number must be a prime

Where as subclass of Rule - RuleItemB Requires the following:

  • The entity must exist
  • The entity must be a string
  • The string must be a valid URL

For sake of argument, lets say there are about 20 different concrete validations in place. I do not want to write all possible permutations of the 20 validations. What I would rather do is the following:

Class RuleItemA Inherits Rule, SubscribesTo(EntityExists,EntityIsNumber,NumberIsPrime)
    Public Overrides Function Validate() As Boolean
         ' Invoke all concrete validations here
    End Function
End Class

I feel like this is similar to traits, or a multi-strategy pattern, but I'm not sure how to implement it.

Is this a known pattern? Is there a way to implement it in .Net?

Was it helpful?

Solution

I do not know the pattern name (but it's probably using the Reflection pattern, see below), but many Web frameworks natively implement what your are trying to do here.

For example if you look at Ruby on Rails, ActiveRecord and Mongoid are the components used to represent a Database entity, and programmers usually implement their model like this :

class User
  include Mongoid::Document # Mongoid is an ORM for MongoDB/noSQL database

  # The attributes of your model
  field :name
  field :email
  field :telephone

  # Validation rules that guarantee consistency of your instances
  validates_presence_of(:name, :email)
  validates_uniqueness_of(:email)
  validates :telephone { maximum: 10}
  ...
end

Then what happens is that everytime you try to save your resource to the database, all the validations will run before and prevent you from saving wrong models.

I would say the best way to go is keep a List of all the Validations that you must run on your class. You could also delegate these validations to a Validator class but here's how I would do it (Java style):

abstract class ValidatableItem
  private List<Validation> toValidate;

  protected validate(Field a, ValidationType type)
    toValidate.push(type.getValidationFor(this, a))
  end

  private boolean runValidations(){
    for(Validation v : toValidate){
      if(v.isNotValid())
        return false;
    }
    return true;
  }

  private Field field(String s){
    return this.getclass.getDeclaredField("s")
  }
}

class ItemA extends ValidatableItem
  Attribute attrA;
  Attribute attrB
  void validations(){
    validate(field("attrA"), ValidationType.EXISTS)
    validate(field("attrB"), ValidationType.NON_NEGATIVE)
  }

And you have to define your Validation / Validation types yourself.

EDIT

Unfortunately I don't see another way but to use Reflection to do that. This can quickly turn into an antipattern. I haven't used reflection a lot in Java, but here's how I would go for it.

class WebPage extends ValidatableItem{
      String url;
      String name;
      int vistiCount;
      Date lastVisit;

      void validations(){
        validate(field("visitCount"), ValidationType.EXISTS)
        validate(field("url"), ValidationType.VALID_URL)
      }
}


public abstract class Validation{
    private Class<? extends ValidatableItem> instanceToValidate;
    private Field fieldToValidate;

    public Validation(Class<? extends ValidatableItem> c, Field f){
        this.instanceToValidate = c;
        this.fieldToValidate = f;
    }
    public abstract boolean isNotValid();
}

class ExistValidation extends Validation{
  // Redefine same constructor as base class, use super()
  public isNotValid(){
    return(f.get(c) == null);
  }
}

class ValidUrlValidation extends Validation{
  // Redefine same constructor as base class, use super()
  public isNotValid(){
    return(urlRegexMatches(f.get(c));
  }
}

Enum ValidationType{
  EXISTS(ExistValidation.class)
  VALID_URL(ValidUrlValidation.class)
  private final Class<? implements Validation> vclass;

  private ValidationTypes(Class<? implements Validation> c){
    this.vclass = c
  }

  public getValidation(Class<? extends ValidatableItem> cl, Field f)
    // Assume all Validation constructors look the same
    return cl.getConstructor(ValidatableItem.class, Field.class).newInstance(cl, f)
}

Note : I don't really understand the context why you need to "validate" your inputs, but unless you need to do very specific things, you can most likely find libraries that already do what you want. Remember the 7 deadly sins of developers.

OTHER TIPS

This sounds like combination of strategy and composite patterns.

Individual validators are strategy pattern. Then, composite is used to invoke multiple strategies as single one.

Licensed under: CC-BY-SA with attribution
scroll top