0

I just answered another question (Select method based on field in class), and I was wondering if the pattern had a name.

Call action.applyX(a), where X depends on some property of a (e.g. type in the example), so you instead call a.apply(action) and let a (or Type) call the appropriate applyX.

Is there a name for that?

public enum Type {
    INTEGER {
        @Override
        public void apply(Action action, A a) {
            action.applyInteger(a);
        }
    },
    STRING {
        @Override
        public void apply(Action action, A a) {
            action.applyString(a);
        }
    };
    public abstract void apply(Action action, A a);
}

public interface Action {
    public void applyInteger(A a);
    public void applyString(A a);
}

public class A {
    private Type type;
    ...
    public void apply(Action action) {
        this.type.apply(action, this);
    }
}

Update

The above is just an example, and using type as the selector is not the important part.

The selection criteria for deciding which X method to call can be anything. In a dice game, X could be 'Odd' or 'Even' and class A could be 'Dice' with a 1-6 int value.

The example is using abstract enum methods as a way to avoid a switch statement (less error prone). The abstract method implementations are a kind of switching technology, in this case the way to choose the appropriate X.

Update 2

This question is about the pattern used to avoid switch statements for doing "action" logic outside of the class (A), not about changing the behavior of A (strategy/policy), where the "switch choices" are well defined, e.g. as a type enum (example above), or by well-known subclasses of A.

As an example, A could define a table column. The class should not be tightly coupled to implementation code, but there will be many different implementation methods ("Actions") that must process column types differently.

Actions might be a call to the appropriate getXxx method on ResultSet, call the appropriate setXxx method on PreparedStatement, format the value for display, render it the XML or Json, parse the value, ...

All these methods would either need a switch statement, or they could implement an interface with the "typed" methods, and ask the class "please call the right one for me".

This question is becoming pretty long. Sorry if I'm not stating the pattern clearly.

Community
  • 1
  • 1
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • 1
    one way of skinning the cat in Strategy Pattern. – Roam Aug 22 '15 at 22:06
  • Dont you hate it when you put up a reasonable question; and then two years later, somebody comes by and downvotes without any explanation? Happened to notice that -2 ... on your activities dashboard. Funny how we both benefited from your comment to my answer this morning that way ;-) – GhostCat May 16 '17 at 06:17
  • I agree that it’s a pattern in that I have seen it many times since I saw my first object-oriented programs in the 1990s. IMHO it’s neither exactly the same as the Visitor nor the Strategy pattern, though I see the relationships with both. In other words, as your question seems to suggest, it would be nice if it had its own name. – Ole V.V. Jul 14 '18 at 10:09
  • [Double dispatch](https://en.wikipedia.org/wiki/Double_dispatch)? – dnault Oct 31 '20 at 00:07

5 Answers5

10

This resembles the Visitor pattern, because you are basically adding new operations to A without changing it (you are externalizing its operations to a separate class).

this.type.apply(action, this);

plays the role of:

visitor.visit(this);

If a new action is added (say applyBoolean), you would need to change the code for A if you used switch statement. However, in your implementation you would just use the new visitor subclass (a new Type enum constant) which implements the code that would otherwise be placed in A.

Andreas
  • 154,647
  • 11
  • 152
  • 247
Dragan Bozanovic
  • 23,102
  • 5
  • 43
  • 110
  • Thank you, that's what I was looking for. The wiki shows example with subclasses, so the interface used method overloading, but since my example used an enum, my interface had to name methods differently. Same pattern. – Andreas Aug 23 '15 at 20:24
  • 3
    @Andreas You were on-point with the "call-inversion" part of your title: https://en.wikipedia.org/wiki/Double_dispatch – michaelsnowden Aug 24 '15 at 21:26
2

This is the beginnings of a Strategy Pattern

Strategy Pattern Wikimedia

It's a Behavorial Pattern, as opposed to the more common Structural Patterns.

In your example you're not taking full advantage of the pattern. Since you use a single interface for all your strategies

In computer programming, the strategy pattern (also known as the policy pattern) is a software design pattern that enables an algorithm's behavior to be selected at runtime.

kervin
  • 11,672
  • 5
  • 42
  • 59
  • The strategy/policy pattern is about changing the behavior of some logic. The pattern in question is not trying to change the behavior of `A`, but to implement some logic *external* to `A`, that's different depending on some property of `A`, normally needing a `switch` statement to implement. – Andreas Aug 22 '15 at 21:52
  • @Andreas a switch is not necessary for Strategy Pattern. Normally it uses assignment to a base type variable, just as you're doing. It can be seen as Inversion Of Control, as the concrete 'Strategy' is passed in as a variable. The behavior of 'A' isn't being **changed**, just alternating strategies **selected** at runtime. – kervin Aug 22 '15 at 23:18
0

I think the name for this is just the name of the language feature used, polymorphism.

Will Angley
  • 1,392
  • 7
  • 11
  • 1
    Isn't polymorphism more about subclassing? Since my example uses `type` as the selector, I can see why polymorphism *might* be appropriate, but my question was intended as more generic. What if the selector was some odd/even test of some integer property of `A`? – Andreas Aug 22 '15 at 17:38
0

Looks like the type decomposition you would find in functional languages

toskv
  • 30,680
  • 7
  • 72
  • 74
  • I'm not well-versed in functional programming. A simple Google search for "type decomposition" didn't seem to come up with a good reference. Do you have a link to an explanation of type decomposition? – Andreas Aug 22 '15 at 17:40
  • seems similar to this. def pCons(list: List[Int]): String = list match { case Nil => "nil" case x::xs => "(" + x + "." + pCons(xs) + ")" } – toskv Aug 22 '15 at 17:41
  • indeed a link seems better. try this: http://ascendant76.blogspot.ro/2012/10/scala-pattern-matching-decomposition.html – toskv Aug 22 '15 at 17:42
  • or this: http://danielwestheide.com/blog/2012/11/21/the-neophytes-guide-to-scala-part-1-extractors.html – toskv Aug 22 '15 at 17:43
  • what both achieve is calling different things based on the type of the argument. – toskv Aug 22 '15 at 17:44
  • But isn't "pattern matching" the same as a `switch` statement? Sure, pattern matching is more flexible, but conceptually it's the same. – Andreas Aug 22 '15 at 17:45
  • They are pretty similar. It's just that in functional languages you are usually able to do it with types as well as values. :) – toskv Aug 22 '15 at 17:47
  • You could just as well use a switch on the Type in this case. :) – toskv Aug 22 '15 at 17:49
  • I added an update to the question, to clarify my question. You are correct, I could use `switch`, but switch statements are inherently error prone, which was the point of using abstract methods on an enum, and why the code is using that "call-inversion" pattern. :-) – Andreas Aug 22 '15 at 17:52
  • I'm out of ideas. I don't know of any OOP patterns that would describe this accurately. :) – toskv Aug 22 '15 at 18:00
0

I would say this is an example of using the strategy pattern. The example in the Wikipedia article (written in C#) also uses an enum.

Mick Mnemonic
  • 7,808
  • 2
  • 26
  • 30
  • I don't see an enum used there. – Andreas Aug 22 '15 at 21:24
  • Sorry, I read the example too hastily. It's not an actual enum, but instead a (enumerable) list on inner classes which implement a common interface. You could write the same thing more elegantly using an enum, though. [This answer](http://stackoverflow.com/a/24435279/905488) actually contains the example rewritten in Java using enums. – Mick Mnemonic Aug 22 '15 at 21:32