Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I have an application object that needs to validate some data. The particular validation algorithm isn't known until runtime, so I pass a validation object to it, using the strategy pattern.

The application might need to reuse the validation object; for example, it might need to perform two validations simultaneously. So ideally, the validation object wouldn't contain any state; it would be purely an algorithm.

But what if the validation algorithm itself needs some state? For example, it might need to keep a list of validation errors.

What's a good approach in this situation? It seems like overkill to create a factory just for this specific validation object.

(Assume this is in a language like Java or PHP.)

share|improve this question
1  
From the example, it sounds like your validation object violates the single responsibility principle. In other words, checking whether something validates and storing a list of errors are two different responsibilities. This leads me to believe that you are missing an object. –  Rein Henrichs Jun 13 '11 at 19:21
    
why would you have a list of validation errors in the validators? Aren't errors belong to the data instead? –  Lie Ryan Jun 14 '11 at 0:03
add comment

4 Answers

up vote 9 down vote accepted

I know I'm being pedantic here, but all objects can have state. The question is whether or not they should have state.

The answer to that question for strategies is the same as the answer for every other kind of inheritance relationship: Yes, as long as you're not violating the Liskov Substitution Principle.

The point of a strategy (or really any other inheritance-based design pattern) is that the caller/owner doesn't care about the implementation. So if the state is initialized either internally or through an instance constructor, and completely self-managed, then state is fine. On the other hand, if the outside world is supposed to be aware of this instance-specific state, then you've got a problem.

In a nutshell, if you find yourself needing to make this state public, then you've probably got a poor design; doubly so if you find yourself doing typecasts from the interface. But private state is, well, private; the whole point of patterns like Strategy is that the caller really doesn't care.

One other thing: Try to avoid sequential coupling. Even though it's OK for the strategy to have state, if the behaviour of the strategy depends significantly on that state then you are wading into dangerous territory, because you have no idea who else is going to try to use this strategy in the future and be unaware of the correct order of operations, so to speak.

share|improve this answer
    
Thanks for the term "sequential coupling" -- I hadn't heard that before. I'm wondering though, doesn't this eventually lead to removing all state from objects that aren't simple data objects? It seems like any other objects would always depend on their state to some degree. –  JW01 Jun 13 '11 at 19:35
    
@JW01: To a certain degree it does; I find that as I refine my own designs over time, I tend to end up with separate implementations for state and behaviour. However, coupling (including sequential coupling) isn't a black-and-white function, it's a continuum. You strive to reduce it but sometimes it's difficult to eliminate completely. What you definitely want to avoid is - for example - having a particular method throw an exception or exhibit some other undocumented behaviour depending on whether or not a method was previously called. –  Aaronaught Jun 13 '11 at 19:40
1  
Can you elaborate on how the Liskov Substitution Principle applies here? What is the type and sub-type in this example? –  Jeremy Jun 13 '11 at 19:59
    
@Jeremy: I thought that was obvious; the type is the abstract strategy and the sub-type is the concrete strategy. You should be able to substitute any concrete strategy and get the same behaviour (as far as what the strategy is actually supposed to do). If the abstract strategy claims to be stateless but some concrete strategy is state-dependent then it violates the LSP - especially if it changes its state and future behaviour as a result of the strategy implementation itself. –  Aaronaught Jun 13 '11 at 20:39
    
@Aaronaught Thanks I think I understand. Since the type is really just an interface what you really mean is that peer implementations should behave the same way given the same operations, which I agree with. There shouldn't be two different strategies for this interface one of which blows up if you don't do state management operations the same way that you must for the other, although this seems a little redundant given your other stipulations. –  Jeremy Jun 13 '11 at 20:53
show 1 more comment

I would consider a logging strategy. You say that your current strategy needs to be possible to use in several different algorithms so I'm assuming you mean instances of said strategy (since otherwise it wouldn't seem to me to matter as much).

What I would consider, and I don't know of course if it'll actually work in your situation, is to put the logging aspect up higher. The strategy in question, needing to log, would then request the log from its owner. Thus the log would be unique to algorithm/owner instance, whatever...even though the strategy might be shared.

share|improve this answer
add comment

For the specific question:

How about breaking it up into:

  • Validator: Manages one or more ValidationStrategy items, maintains a list of listeners for validation errors.
  • ValidationStrategy: Actually does the validation based on rules
  • ValidationListener: Interface implemented by any code interested in hearing about failures and tallying them up.

So "listener management" is kept separate from "recording errors" which is separate from "finding errors".


Broader question: I think the kind of state matters here.

Acceptable state includes stuff which lets you avoid creating a dozen redundant classes. For example:

public class SimpleStyling implements TextFormatStrategy{
    boolean bold = false;
    boolean italic = false;
    boolean underlined = false;

    /* Assume getters and setters for each */

    public String formatText(String input){
        /* ... */
    }
}

In contrast, the bad kind of state would be stuff which "leaks across jobs".

public class SimpleStyling implements TextFormatStrategy{
    MyFormat styleUsedInPreviousInvocation = ...;
}
share|improve this answer
    
It wouldn't necessarily need to be used across jobs in order to be a problem. If "MyFormat" is a reference type which requires initialization, and the "SimpleStyling" class doesn't auto-initialize it, then this breaks the strategy contract by adding a hidden precondition. By contrast, the version with boolean properties does not have a precondition, just default/modifiable behaviour. Still, I don't like either design; the "good" version should be immutable, and those fields/properties should be read-only, initialized in the constructor. Otherwise you leak history if the instance is reused. –  Aaronaught Jun 13 '11 at 21:39
add comment

Should strategy objects have state?

The Gang of Four Design Patterns book does have a few things to say about state being contained within the Strategy pattern.

There are two methods described for containing state:

  • Provide the Strategy with any state information that it needs. The interface defines various methods and the parameters that are needed for the Strategy to perform its task.
  • Allow the context to provide itself to the Strategy, either at the creation of the Strategy or when the Strategy is executed. The Strategy can access only the data that is needed through the specified interface.

The first option leads to a decoupled Strategy and Context. The second option leads to a tighter coupling between the Strategy and Context. You might want to consider the coupling/cohesion factor when choosing an implementation of Strategy.

Strategies increase the number of objects in an application. Sometimes you can reduce this overhead by implementing strategies as stateless objects that contexts can share. Any residual state is maintained by the context, which passes it in each request to the Strategy object. Shared strategies should not maintain state across invocations. The Flyweight (195) pattern describes this approach in more detail.

What this says is that typically, the state needed to carry out the Strategy is maintained within the context. This allows Strategies to be shared among various contexts without concern of an invalid state being contained. As long as the context has a valid state, that valid state will be guaranteed to be operated upon by the Strategy since it is provided as needed.


What's a good approach in this situation?

In your situation, I would consider not storing this information in the Strategy at all. It has nothing to do with the execution, but rather the result of the validation algorithm.

If you need to maintain data about success/failure, there are multiple points of failure, and you don't stop the algorithm after the first failure, I would consider the second implementation that I described above, where you pass the Context into the Strategy. Using a callback, the Context maintains a collection of validation errors. Every time a Strategy encounters an error, it simply calls a specified method in the Context to add information.

...it might need to perform two validations simultaneously...

Because of this, my approach would consist of a data structure such as a map in the Context. The map would be a mapping between Strategy and validation error, or perhaps a map between Strategy and a collection of validation errors.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.