2013-04-01 103 views
1

我有一些类Base的实现,并且所有对象都收集在List<Base>中。如何根据对象instanceof选择要执行的操作?

如何根据instanceof这些对象调用特定的action而不必使用详细的instanceof检查?我怎样才能根据这些对象的实例选择一个service方法来执行,而不必关心执行哪个对象。应该以某种方式自动选择正确的服务方法,而不用指定类型或实例检查。

class Base; 
class Foo extends Base; 
class Bar extends Base; 

class Service { 
    List<Base> bases; 

    public void someMethod() { 
     for (Base base : bases) { 
      //perform some instanceof dependend action. 
      //these actions cannot be inside of any Base class as it makes use of other objects too. 
      if (base instanceof Foo) { 
       fooService.action((Foo) base); 
      } 
      if (base instanceof Bar) { 
       barService.action((Bar) base); 
      } 
     } 
    } 
} 


//custom service methods 
class FooService { 
    void action(Foo foo) { 
    } 
} 

class BarService { 
    void action(Bar bar) { 
    } 
} 
+2

这种反模式的气味。战略模式可以在更少的情况下使用更脆弱的实例吗? –

+1

或者使用某种工厂来加载服务方法。 – Marvo

+0

那么,对于一个“策略”,我首先必须知道我正在处理的是哪个“Base”实例,对吧?因为我最终会遇到'FooStrategy'和'BarStrategy',如果我想在所有'Foo'实例上调用'FooStrategy',我必须首先执行'instanceof'检查... – membersound

回答

4

多态性是一种可能性。如果Base类包含抽象action()方法,则可以直接调用它,而不使用if语句。

另一个是注册表。对于Base的每个子类,您都可以将映射注册到服务类。在someMethod()中,查找注册表中的类,获取相应的服务类,然后调用它。

顺便说一下,冗长并不是instanceof语句的唯一问题。一旦创建了Base的新子类,您用这些代码编写的代码就会中断。满足Open/Closed principle可能会导致代码不易损坏。

+0

是的,但是如上所述,我不能在我的Base类中使用'action()',因为它更像是一个服务方法,它也可以使用其他对象。否则在多态性方面很容易,但我正在寻找一种方法来处理这个问题,而不必将逻辑放在'Base'实现中。 – membersound

+0

你有没有考虑过第二种可能性 - 一个注册表? –

+0

是的,这可能是我唯一可以去的方式,尽管我对注册表查找并不感到满意。从设计的角度来看,它也感觉不对。那么改变'Base'对象并引入'getService()'方法可能会更好,这样每个实现都会被迫提供它自己的服务。 – membersound

2

一种可能的解决方案是使用Visitor模式。您需要将FooServiceBarService合并成一个类,并且这两种方法都有超载的action()方法。然后,您需要将accept()方法添加到FooBar类别中的每一个类别,然后可以调用相应的action()方法。欲了解更多详情,请参阅http://en.wikipedia.org/wiki/Visitor_pattern

有可能是其他更合适的design patterns可以解决这个问题。我建议你研究一下。

+0

确定那很好,但是:如果我喜欢这些特定于实例的方法中的5个,该怎么办?这意味着我必须写5个访问者,并为每个新的实例依赖行为创建一个新的访问者。 – membersound

+0

@member由“特定于实例”的方法,你的意思是每个Service类中有5个方法吗?如果是这样,那么你几乎肯定会需要使用不同的设计模式。我确信通过一些研究,你可以找到适合你需求的东西。 –

+0

是的,比方说我有一些'add(),delete(),modify(),update()'方法。它们中的每一个都应该依赖于实例,这意味着'Foo'的add()'应该与'Bar'的'add()'不同。无论如何,我想保留所有'基本'对象在'List '中,并且通过迭代在列表中执行'add(base)'...您是否有更好设计的建议。因为我在这里问的是,我自己到目前为止还没有找到一个更好的... – membersound

0

我曾经得到解决这个问题最接近的是:

class Base{}; 
class Foo extends Base{}; 
class Boo extends Base{}; 

附加BaseService接口,因此每个服务类中使用同样的方法:

public interface BaseService<T extends Base> { 

void action(T base); 

} 

BooService:

public class BooService implements BaseService<Boo> { 

public void action(Boo boo){ 
    System.out.println("Action performed by BooService"); 
    } 
} 

FooService:

public class FooService implements BaseService<Foo> { 

public void action(Foo foo){ 
    System.out.println("Action performed by FooService"); 
    } 
} 

附加ServiceSupplier类,将通过对象调用适当的服务基地:

public class ServiceSupplier { 

private Map<Class<? extends Base>, BaseService> services; 

public ServiceSupplier(){ 
    initializeServiceMap(); 
} 

public BaseService getServiceOfType(Class<? extends Base> clazz){ 
    return services.get(clazz); 
} 

private void initializeServiceMap() { 
    services = new HashMap<>(); 
    services.put(Foo.class, new FooService()); 
    services.put(Boo.class, new BooService()); 
    } 
} 

和您的服务类:

public class Service { 
List<Base> bases; 
ServiceSupplier serviceSupplier; 

public Service(){ 
    serviceSupplier = new ServiceSupplier(); 

    bases = new ArrayList<>(Arrays.asList(new Foo(), new Boo())); 
} 

public void someMethod() { 
    bases.forEach(base -> serviceSupplier.getServiceOfType(base.getClass()).action(base)); 
    } 
} 

可能看起来就像刚刚去除几个“如果”声明,但有更多的服务,你需要做的就是将它们添加到initializeServiceMap()方法。

相关问题