Visitor implementation and enum 1.5

I have an application with enum, that's behaviour changes based on the value of the enumerated type, see http://java.sun.com/developer/JDCTechTips/2005/tt0208.html#2 for more detail.

The problem that I see in this Design Pattern that client of the enum should decide what VisitorImpl should be created.

I have a situation, when another application calls me and passes me the enum. Let say it is outer client. Based on the enum my application (inner client of the enum) should create appropriate Visitor and call the Enum. In my case there is only one behaviour. I don't want to add switch on enum or use hashMap in order to decide which Visitor should be created.

For example, something like this

publicclass Container{

privatestatic Map<B, Visitor> cache =new EnumMap<B, Visitor>(B.class);

static{

cache.put(B.PENNY, Inner.PENNY_VISITOR);

cache.put(B.NICKEL, Inner.NICKEL_VISITOR);

cache.put(B.DIME, Inner.DIME_VISITOR);

cache.put(B.QUARTER, Inner.QUARTER_VISITOR);

}

public Visitor getDefaultVisitor(B enumValue){

return cache.get(enumValue);

}

}

Note: it is possible to cache not Visitor, getDefaultVisitor() behaviour, but directly accept() behaviour and avoid to use Visitor pattern at all. What's wrong with this?

I found elegant solution. Does it correct?

publicinterface Visitor{

publicvoid visit(B b);

}

publicenum B{

PENNY{void accept(Visitor v){ v.visit(this);}

Visitor getDefaultVisitor(){return Inner.PENNY_VISITOR;}

},

NICKEL{void accept(Visitor v){ v.visit(this);}

Visitor getDefaultVisitor(){return Inner.NICKEL_VISITOR;}

},

DIME{void accept(Visitor v){ v.visit(this);}

Visitor getDefaultVisitor(){return Inner.DIME_VISITOR;}

},

QUARTER{void accept(Visitor v){ v.visit(this);}

Visitor getDefaultVisitor(){return Inner.QUARTER_VISITOR;}

};

abstractvoid accept(Visitor v);

abstract Visitor getDefaultVisitor();

privatestaticclass Inner{

privatestaticfinal Visitor PENNY_VISITOR =new Visitor(){

publicvoid visit(B b){

//add actual body

System.out.println("You are in the PENNY_VISITOR with paramater "+b);

}

};

privatestaticfinal Visitor NICKEL_VISITOR =new Visitor(){

publicvoid visit(B b){

//add actual body

System.out.println("You are in the NICKEL_VISITOR with paramater "+b);

}

};

privatestaticfinal Visitor DIME_VISITOR =new Visitor(){

publicvoid visit(B b){

//add actual body

System.out.println("You are in the DIME_VISITOR with paramater "+b);

}

};

privatestaticfinal Visitor QUARTER_VISITOR =new Visitor(){

publicvoid visit(B b){

System.out.println("You are in the QUARTER_VISITOR with paramater "+b);

//add actual body

}

};

}

}

publicclass Client{

publicstaticvoid main(String[] args){

callInnerClient(B.PENNY);

callInnerClient(B.NICKEL);

callInnerClient(B.DIME);

callInnerClient(B.QUARTER);

}

publicstaticvoid callInnerClient(B enumValue){

Visitor v = enumValue.getDefaultVisitor();

enumValue.accept(v);

}

}

Note: 1)because I have only one behaviour to simulate and its represented object is stateless, Singleton Design Pattern was used. Because Visitor implementation is defined in inner class they will be initialized only when one them will be initialized. They can be splited out to different class in order to make them truly lazy.

2) The implementation is flexible. If new behaviour will be added in the future, it should just implement interface Visitor. It can be passed to enum and used. Alternatively, new getNeVisitor() method could be added.

So, my questions are

1) Does this is correct implementation of Visitor pattern?

2) Why Visitor pattern could not be implemented using HashMap (or EnumMap in this case)?

[7928 byte] By [alexsmaila] at [2007-11-27 11:52:32]
# 1

Any comments?

alexsmaila at 2007-7-29 18:45:03 > top of Java-index,Other Topics,Patterns & OO Design...
# 2

> Any comments?

Your writing is very difficult to understand. As a result, readers will not be able to identify what your topic is about. For example, your question

"Does this is correct implementation of Visitor pattern?"

The grammar of this sentence is poor. You should try to write better English. This effort may help you write better Java.

In regards to your post, could you explain the business requirement that this code is supposed to satisfy?

GhostRadioTwoa at 2007-7-29 18:45:03 > top of Java-index,Other Topics,Patterns & OO Design...
# 3

> > Any comments?

>

> Your writing is very difficult to understand. As a

> result, readers will not be able to identify what

> your topic is about. For example, your question

>

> "Does this is correct implementation of Visitor

> pattern?"

>

> The grammar of this sentence is poor. You should try

> to write better English. This effort may help you

> write better Java.

>

> In regards to your post, could you explain the

> business requirement that this code is supposed to

> satisfy?

Sorry for my English. It is not my native language.

"Does this is correct implementation of Visitor

pattern?" should be readed as "Is this correct implementation of Visitor

pattern?"

The following text will be copied to the original message, that I will rewrite in the following message.

Business requirement is the following. My application is called from another 2-3 applications. Depends which application making a call there is slightly different behaviour in one well-defined point. My application should change its behaviour depends on what outer application calls.

From the design point of view, another application (they are written in Java) can pass enum in their entry point. I can save this enum in some well-defined place, and when I'll reach the point (I'll call it deciding point), where behaviour is somewhat different, I'll change it according to the enum specified.

First approach is to make switch in that place, based on enum. Enhancement is to use HashMap (see class Container). I don't see any problem with this approach, but it is nonstandard way.

Second approach say to use Design Pattern Visitor. But I don't really understand how the correct Visitor can be instantiated. I suggest to tie Visitor to the ApplicationEnum. In such a case, another application (I'll call it outer client) pass only enum, when deciding point is reached (this code I'll call inner client, that is client that actually use the Design Pattern Visitor) default visitor is obtained and passed to the enum accept method in the standard way. Because, in my case, default visitor has no state, I suggest to make him Singleton.

Note: Associating of the default Visitor with enum is not very restricted. One can create another Visitor in the standard way and pass it to enum. I just see no reason that outer client (another application) will create Visitor. This implementation detail should be hidden from it.

Message was edited by:

alexsmail

alexsmaila at 2007-7-29 18:45:03 > top of Java-index,Other Topics,Patterns & OO Design...
# 4

This is rewritten original post.

I have an application with enum, that's behaviour changes based on the value of the enumerated type, see http://java.sun.com/developer/JDCTechTips/2005/tt0208.html#2 for more detail.

The problem that I see in this Design Pattern that client of the enum should decide what VisitorImpl should be created.

I have a situation, when another application calls me and passes me the enum. Let say it is outer client. Based on the enum my application (inner client of the enum) should create appropriate Visitor and call the Enum. In my case there is only one behaviour. I don't want to add switch on enum or use hashMap in order to decide which Visitor should be created.

For example, something like this

public class Container {

private static Map<B, Visitor> cache = new EnumMap<B, Visitor>(B.class);

static {

cache.put(B.PENNY, Inner.PENNY_VISITOR);

cache.put(B.NICKEL, Inner.NICKEL_VISITOR);

cache.put(B.DIME, Inner.DIME_VISITOR);

cache.put(B.QUARTER, Inner.QUARTER_VISITOR);

}

public Visitor getDefaultVisitor(B enumValue){

return cache.get(enumValue);

}

}

Note: it is possible to cache not Visitor, getDefaultVisitor() behaviour, but directly accept() behaviour and avoid to use Visitor pattern at all. What's wrong with this?

I found elegant solution. Does it correct?

public interface Visitor {

public void visit(B b);

}

public enum B {

PENNY { void accept(Visitor v){ v.visit(this);}

Visitor getDefaultVisitor(){return Inner.PENNY_VISITOR;}

},

NICKEL { void accept(Visitor v){ v.visit(this);}

Visitor getDefaultVisitor(){return Inner.NICKEL_VISITOR;}

},

DIME { void accept(Visitor v){ v.visit(this);}

Visitor getDefaultVisitor(){return Inner.DIME_VISITOR;}

},

QUARTER {void accept(Visitor v){ v.visit(this);}

Visitor getDefaultVisitor(){return Inner.QUARTER_VISITOR;}

};

abstract void accept(Visitor v);

abstract Visitor getDefaultVisitor();

private static class Inner {

private static final Visitor PENNY_VISITOR = new Visitor(){

public void visit(B b){

//add actual body

System.out.println("You are in the PENNY_VISITOR with paramater "+b);

}

};

private static final Visitor NICKEL_VISITOR = new Visitor(){

public void visit(B b){

//add actual body

System.out.println("You are in the NICKEL_VISITOR with paramater "+b);

}

};

private static final Visitor DIME_VISITOR = new Visitor(){

public void visit(B b){

//add actual body

System.out.println("You are in the DIME_VISITOR with paramater "+b);

}

};

private static final Visitor QUARTER_VISITOR = new Visitor(){

public void visit(B b){

System.out.println("You are in the QUARTER_VISITOR with paramater "+b);

//add actual body

}

};

}

}

public class Client {

public static void main(String[] args) {

callInnerClient(B.PENNY);

callInnerClient(B.NICKEL);

callInnerClient(B.DIME);

callInnerClient(B.QUARTER);

}

public static void callInnerClient(B enumValue){

Visitor v = enumValue.getDefaultVisitor();

enumValue.accept(v);

}

}

Note: 1)because I have only one behaviour to simulate and its represented object is stateless, Singleton Design Pattern was used. Because Visitor implementation is defined in inner class they will be initialized only when one them will be initialized. They can be splited out to different class in order to make them truly lazy.

2) The implementation is flexible. If new behaviour will be added in the future, it should just implement interface Visitor. It can be passed to enum and used. Alternatively, new getNeVisitor() method could be added.

So, my questions are

1) Does this is correct implementation of Visitor pattern?

2) Why Visitor pattern could not be implemented using HashMap (or EnumMap in this case)?

alexsmaila at 2007-7-29 18:45:03 > top of Java-index,Other Topics,Patterns & OO Design...
# 5

> Business requirement is the following. My application

> is called from another 2-3 applications.

Why do users use these applications? What purpose do the applications server? Why is your application called by the others?

What is your application supposed to do?

> From the design point of view, another application

> (they are written in Java) can pass enum in their

> entry point. I can save this enum in some

> well-defined place, and when I'll reach the point

> (I'll call it deciding point), where behaviour is

> somewhat different, I'll change it according to the

> enum specified.

Ok. What is the normal behavior of your application? What are the changes in behavior that are based upon the values specified in the enum?

>

> First approach is to make switch in that place, based

> on enum. Enhancement is to use HashMap (see class

> Container). I don't see any problem with this

> approach, but it is nonstandard way.

What do you think is the standard way? Why do you think this is the standard way?

> Second approach say to use Design Pattern Visitor.

> But I don't really understand how the correct Visitor

> can be instantiated.

There is no one correct way to implement the Visitor design pattern. There can be many, many ways to implement the pattern. Each one of them may be good. None of them are the "correct" way. You can implement the pattern using a HashMap where applicable. This is fine.

GhostRadioTwoa at 2007-7-29 18:45:03 > top of Java-index,Other Topics,Patterns & OO Design...
# 6

First of all I want to thank you for your time.

> > Business requirement is the following. My

> application

> > is called from another 2-3 applications.

>

> Why do users use these applications? What purpose do

> the applications server? Why is your application

> called by the others?

> What is your application supposed to do?

My application is in VoIp area. It has business logic. It can be called from our web-site as back-end, it can be called also by another firm as Web-Servise (through SOAP) or even from another application in my firm by directly Java call. For example, customer want to open his account to make calls. He basically has 3 options. He can log in to http://www.pingo.com to create his account, recharge it with initial amount of money and start to talk. This is our UI calls back-end. He can go to the shopping center and he can bye calling card. When he will be pay off the money, this credit card will be activated through the Web-Service. In the next release, he will be able to recharge his account moment before he make a call by phone. It is yet another application that calls business logic. You can read more about my firm here http://www.ibasis.com/ In additional to the retail services iBasis is also gives infrastructure to the phone providers. For example, to Vodafone company, see http://www.vodafone.com/

> > From the design point of view, another application

> > (they are written in Java) can pass enum in their

> > entry point. I can save this enum in some

> > well-defined place, and when I'll reach the point

> > (I'll call it deciding point), where behaviour is

> > somewhat different, I'll change it according to

> the

> > enum specified.

>

> Ok. What is the normal behavior of your application?

> What are the changes in behavior that are based upon

> the values specified in the enum?

>

The normal behaviour is that when recharge is make from our UI some specific id is logged in to DB. If, for example, it is direct Java call, than another id is logged in to DB. In the future, behaviour will be change. Besides of using different id for reporting purpose, bonus amount will be calculated differently to encourage customers to prefer one way to another.

> >

> > First approach is to make switch in that place,

> based

> > on enum. Enhancement is to use HashMap (see class

> > Container). I don't see any problem with this

> > approach, but it is nonstandard way.

>

> What do you think is the standard way? Why do you

> think this is the standard way?

>

See http://java.sun.com/developer/JDCTechTips/2005/tt0208.html#2 that references to "Design Patterns: Elements of Reusable Object-Oriented Software" http://www.awprofessional.com/title/0201633612

> > Second approach say to use Design Pattern Visitor.

> > But I don't really understand how the correct

> Visitor

> > can be instantiated.

>

> There is no one correct way to implement the Visitor

> design pattern. There can be many, many ways to

> implement the pattern. Each one of them may be good.

> None of them are the "correct" way. You can implement

> the pattern using a HashMap where applicable. This is

> fine.

Strength of Desing pattern is to supply unified implementation in the common scenarios. This implementation is typically differ form one language to another, but within language there is typically one or two standard/recommended way. The point is to avoid pitfalls that another people felt into. So, it can be the case that HashMaps approach is avoided because of some pitfall that I haven't discovered yet. It can be also, as you mentioned, that it is possible to implement Visitor Desing Pattern also by HashMap. In such a case, what approach should I prefer in my case?

alexsmaila at 2007-7-29 18:45:03 > top of Java-index,Other Topics,Patterns & OO Design...