Re: Visitor pattern vs if-ladder
Philipp wrote:
As I wrote in my answer to Albert, the same code is shared between a
client and a server. I don't want to include methods in the shared
classes which will only be of use to one side. I am thinking about
using an aggregated class, where calls to methods of the simpler,
shared class are delegated to an instance of it, and additional
methods are implemented. But as far as I see, this will result in the
ladder being in the factory.
I dug out Effective Java by Joshua Bloch. He goes into factory patterns
in that book, including the Service Provider pattern. I stole his idea
and implemented a short example below how it might work. You should get
his book, good stuff in there. My code below is almost exactly what
Bloch uses as his example.
Note Bloch uses the same "look it up in a map" pattern as Patricia
suggested. Bloch uses Strings, not Class, as the key, but the result is
the same. You might consider Strings -- nothing wrong with asking for a
"CarWrapper" instead of asking for a CarWrapper.class.
The classes below with a single // comment after the class name are my
implementations of Bloch's pattern. Bloch uses three classes: Service,
Provider, and Services.
package fubar;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ServiceProvider {
public static void main( String[] args )
{
Vehicle[] tests = { new Car(), new Truck(),
new Scooter(), };
test( tests );
VehicleWrappers.registerNewWrapper( Scooter.class,
new ScooterdWrapperProvider() );
test( tests );
}
private static void test( Vehicle[] tests )
{
for( Vehicle v : tests ) {
try {
System.out.println( "wrapper: " + VehicleWrappers.
newInstance( v ) );
}
catch ( IllegalArgumentException x ) {
System.out.println( "wrapper: " + x );
}
}
}
}
interface VehicleWrapper { // Service
void incCount();
int getCount();
}
interface VehicleWrapperProvider // Provider
{
VehicleWrapper newVehicleWrapper();
}
class VehicleWrappers // Services
{
private VehicleWrappers() { }
private static final Map<Class<? extends Vehicle>,
VehicleWrapperProvider> providers =
new ConcurrentHashMap<Class<? extends Vehicle>,
VehicleWrapperProvider>();
static {
// default providers
providers.put( Car.class, new CarWrapperProvider() );
providers.put( Truck.class, new TruckWrapperProvider() );
}
public static void registerNewWrapper(
Class<? extends Vehicle> type,
VehicleWrapperProvider provider )
{
providers.put( type, provider );
}
public static VehicleWrapper newInstance( Vehicle v ) {
VehicleWrapperProvider vwp = providers.get( v.getClass() );
if( vwp == null) {
throw new IllegalArgumentException( "No provider for: " +
v.getClass() );
}
return vwp.newVehicleWrapper();
}
}
class CarWrapperProvider implements VehicleWrapperProvider {
public VehicleWrapper newVehicleWrapper()
{
return new CarWrapper();
}
}
class TruckWrapperProvider implements VehicleWrapperProvider {
public VehicleWrapper newVehicleWrapper()
{
return new TruckWrapper();
}
}
class ScooterdWrapperProvider implements VehicleWrapperProvider {
public VehicleWrapper newVehicleWrapper()
{
return new ScooterWrapper();
}
}
class CarWrapper implements VehicleWrapper {
Car wrapped;
int count;
public void setWrapped( Car wrapped ) {
this.wrapped = wrapped;
}
public void incCount() {
count++;
}
public int getCount() {
return count;
}
}
class TruckWrapper implements VehicleWrapper {
Truck wrapped;
int count;
public void setWrapped( Truck wrapped ) {
this.wrapped = wrapped;
}
public void incCount() {
count++;
}
public int getCount() {
return count;
}
}
class ScooterWrapper implements VehicleWrapper {
Scooter wrapped;
int count;
public void setWrapped( Scooter wrapped ) {
this.wrapped = wrapped;
}
public void incCount() {
count++;
}
public int getCount() {
return count;
}
}
class Vehicle{}
class Car extends Vehicle {}
class Truck extends Vehicle {}
class Scooter extends Vehicle {}