有这种模式吗?公共基类,对某些子类具有特殊操作

时间:2010-09-14 19:27:34

标签: java design-patterns

我有代码,当给出一个东西时,它需要理清它是什么特定的东西,然后采取基于此的特殊行动。可能的类是desc

public void doSomething(BaseThing genericThing) 
{
  if (genericThing instanceof SpecificThing)
  {
    SpecificThingProcessor stp = new SpecificThingProcessor((SpecificThing) genericThing);
  }
  else if (genericThing instanceof DifferentThing)
  {
    DifferentThingProcessor dtp = new DifferentThingProcessor((DifferentThing) genericThing);
  }
  else if (genericThing instanceof AnotherThing){
    AnotherThingProcessor atp = new AnotherThingProcessor((AnotherThing) genericThing);
  }
  else
  {
    throw new IllegalArgumentException("Can't handle thing!");
  }
}

有没有一种模式或更好的处理方法?不幸的是,正在执行的操作不适合围绕BaseThing进行泛化,它们必须针对每个特定类别的事物进行。

7 个答案:

答案 0 :(得分:11)

我能想到的最佳选择是将功能抽象到接口中,并使每种类型都实现该接口。

如果你根据类型添加一些关于你想要做的事情的更多细节,我可以提出一个更好的建议(可能有一些示例代码)。

修改

编辑之后,肯定有一种明确的方法可以做到这一点。每个处理器将实现特定的接口:

public interface IProcessor
{
    void Process();
}

public class SpecificThingProcessor : IProcessor
{
    public void Process() { /* Implementation */ }    
}

public class DifferentThingProcessor : IProcessor
{
    public void Process() { /* Implementation */ }
}

public class AnotherThingProcessor : IProcessor
{
    public void Process() { /* Implementation */ }
}

每个BaseThing必须实现一个返回特定处理器的方法:

public abstract class BaseThing
{
    public abstract IProcessor GetProcessor();
}

public class SpecificThing : BaseThing
{
    public override IProcessor GetProcessor()
    {
        return new SpecificThingProcessor();
    }
}

public class DifferentThing : BaseThing
{
    public override IProcessor GetProcessor()
    {
        return new DifferentThingProcessor();
    }
}

然后你的方法就是:

public void doSomething(BaseThing genericThing)
{
    IProcessor processor = genericThing.GetProcessor();
    processor.Process();
}

答案 1 :(得分:10)

您应该在BaseThing中定义一个方法,以便被特定的东西覆盖。

换句话说,您应该使用virtual function


  

正在执行的操作不是   在通用的东西上执行。   根据具体类型,a   “制片人”课程需要   实例化以处理正确的   事物的类型。这是不合适的   从中调用制作人   BaseThing子类

您仍然可以执行: thing.GetProcessor(),并让每件事都返回其用于它的特定处理器。处理器当然会实现一个通用接口或基类。

对于另一种选择,这会达到我的java限制,但我确信你应该可以沿着这些行做某些事情

  • 存储类型,处理器构造函数的列表/字典。
  • 获取您正在接收的genericThing实例的类型
  • 在列表中搜索类型并调用相应的构造函数。

答案 2 :(得分:3)

访客模式正是您想要实现的目标。但是,“良好的老式多态”应该可以满足您的需求。例如:

abstract class BaseThing {
    abstract public void doSomething();
}

class ThingA extends BaseThing {
    public void doSomething() {
        System.out.println("ThingA...");
    }
}

class ThingB extends BaseThing {
    public void doSomething() {
        System.out.println("ThingB...");
    }
}

class ThingC extends BaseThing {
    public void doSomething() {
        throw new UnsupportedOperationException("Cannot call this on ThingC");
    }
}

然后

class ThingHandler {
    public void doSomething(BaseThing thing) {
         try {
             thing.doSomething();
         } catch (UnsupportedOperationException e) {
             throw new IllegalArgumentException("Can't handle thing!");
         }
    }
}

因此

ThingHandler handler = new ThingHandler();

handler.doSomething(new ThingA());  // -> ThingA...
handler.doSomething(new ThingB());  // -> ThingB...
handler.doSomething(new ThingC());  // -> IllegalArgumentException: Can't handle thing!

你已经提到“它需要弄清楚它是什么类型的东西”,所以现在你需要的是BaseThing有一个抽象方法,它将返回Comparator和每个{ {1}}等将实现它并返回ThingA类的正确comparator进行排序。每个ThingHandler实现都可以执行特定操作或返回BaseThing中所需的某种值(您甚至可以在ThingHandler方法中传递ThingHandler实例。 ..)

但如果Visitor pattern真的是你需要的,这里有一个例子供你满足:

BaseThing.doSomething

然后

interface IThing {
   public void accept(ThingHandler handler);
}
interface IThingHandler {
   public void visit(ThingA a);
   public void visit(ThingB b);
   //...
}

class ThingA implements IThing {
   public void accept(IThingHandler h) {
      h.visit(this);
   }
   public String getSomeValueA() {
      return "Thing A";
   }
}

class ThingB implements IThing {
   public void accept(IThingHandler h) {
      h.visit(this);
   }
   public String getSomeValueB() {
      return "Thing B";
   }
}

// ...

class ThingHandler implements IThingHandler {
   public void visit(ThingA thing) {
       // sort according to ThingA
       System.out.println(thing.getSomeValueA() + " has visited");
       doSomething(thing);
   }
   public void visit(ThingB thing) {
       // sort according to ThingB
       System.out.println(thing.getSomeValueB() + " has visited");
       doSomething(thing);
   }

   private void doSomething(IThing thing) {
       // do whatever needs to be done here
   }
}

但是因为这意味着每次实现新的IThingHandler handler = new ThingHandler(); new ThingA().accept(handler); // -> Thing A has visited new ThingB().accept(handler); // -> Thing B has visited //... 类时都要维护IThingHandler接口,所以我更喜欢建议模式的第一个修改/简化实现。但是,您可以随意适应模式以满足您的需求,并且不要因为它完全看起来像描述的访问者模式而停止自己。

要问的两个问题是

  • “谁负责处理这项行动?”
  • “谁负责持有执行操作所需的数据?”

我通常喜欢将大部分混凝土保存在同一个地方并在其他地方推广;它有助于维护(例如添加和删除功能)。虽然访问者模式有助于将操作集中在同一个类......

答案 3 :(得分:1)

这听起来像是面向对象编程的基本思想之一。您创建一个声明doSomething的超类,然后创建子类,每个子类以不同方式实现它。那就是:

public class BaseThing
{
  abstract public void doSomething();
}
public class SpecificThing extends BaseThing
{
  public void doSomething()
  {
    System.out.println("I'm a SpecificThing!");
  }
}
public class DifferentThing extends BaseThing
{
  public void doSomething()
  {
    System.out.println("I'm a DifferentThing!");
  }
}
public class AnotherThing extends BaseThing
{
  public void doSomething()
  {
    System.out.println("I'm an AnotherThing!");
  }
}

如果由于某种原因你真的需要将“东西”作为参数传递,那好吧。做以上,然后写:

void doSomething(BaseThing genericThing)
{
  genericThing.doSomething();
}

如果你的某些子类不能执行该函数并且应该给出错误消息,那么只需在超类型中使其成为abstrct,使超类型执行“无效”处理,如:

public void BaseThing
{
  public void doSomething()
    throws IllegalArgumentException
  {
    throw new IllegalArgumentException("Can't handle this thing");
  }
}

答案 4 :(得分:1)

问题在于战略模式的教科书范例。您将特定的行为提取到单独的类中,这些类实现了相同的接口(使用类似doIt()的方法)。然后,您为每个特定的类提供对“行为”的引用 - 您希望它具有的对象。 奖金: 1)您可以通过简单地给它另一个“行为”对象来改变运行时对象的行为。 2)你不必覆盖一个方法(重写方法的危险可能是阶级性的)。

答案 5 :(得分:0)

在尝试强制使用模式之前,可以使用普通的旧OO多态进行处理 您不必为处理器创建子类,您可以在单个Processor类中重载方法声明,保持方法名称相同,但声明特定类型的参数。

void foo(BaseTing ting) { System.out.println("Default " + ting.name); }

void foo(TingA ting) { System.out.println("AA " + ting.name); }

void foo(TingB ting) { System.out.println("BB " + ting.name); }

Java将解析与参数类型最匹配的方法,因此如果你有TingC扩展TingB,那么将调用foo(TingB),直到在Processor类中定义了foo(TingC)。

如果您要为每种类型的东西添加更多动作,即baz(Ting),bar(Ting),bat(Ting)等,那么您可能想要通过Ting子类型拆分处理器类并使用用于创建特定处理器和策略模式的工厂方法 即BaseProcessor,TingAProcessor,TingBProcessor BaseProcessor可以很好地容纳工厂方法,并且应该为每个方法提供默认实现,即使默认实现是抽象的或只是抛出异常。专用的Processors类应该从BaseProcessor扩展并继承和覆盖默认操作。

答案 6 :(得分:0)

你几乎没有选择:
*将您的功能抽象到界面中,让其他类实现该界面 *您可以使用Chain of responsibility patternconsisting of a source of command objects and a series of processing objects
。 *您还可以使用Strategy design pattern algorithms can be selected at runtime