代码之家  ›  专栏  ›  技术社区  ›  Freiheit

这有规律吗?对某些子类具有特殊操作的公共基类

  •  1
  • Freiheit  · 技术社区  · 14 年前

    我有一个代码,当给定一个东西时,它需要找出它是什么样的特定类型的东西,然后根据它采取特殊的行动。可能的类都是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!");
      }
    }
    

    7 回复  |  直到 6 年前
        1
  •  11
  •   Justin Niessner    14 年前

    我能想到的最好的选择是将功能抽象到接口中,并让每个类型实现该接口。

    编辑

    经过编辑,肯定有一个明确的方法来做到这一点。每个处理器将实现一个特定的接口:

    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 */ }
    }
    

    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();
    }
    
        2
  •  10
  •   eglasius    14 年前

    换句话说,你应该使用 virtual function .


    正在执行的操作不正确 在一般的东西上执行。 根据其具体类型 “制片人”班需要 什么类型的东西。这是不合适的 从电视台给制片人打电话

    你仍然可以:

    另一种选择 应该能按照这些思路做些事情 :

    • 存储类型、处理器构造函数的列表/字典。
    • 在列表中搜索类型并调用相应的构造函数。
        3
  •  3
  •   Yanick Rochon    14 年前

    访客模式正是你想要达到的。然而,一个“好的老式多态性”应该可以满足您的需要。例如:

    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 以及每个 ThingA 等将执行并返回正确的 comparator 对于 ThingHandler 要排序的类。每个 卑鄙的 实现可以执行特定的操作,或者返回您需要的某种值 物品处理者 中的实例 BaseThing.doSomething 方法…)

    但是如果 Visitor pattern 是你真正需要的,以下是你需要的一个例子:

    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 每次一个新的 IThing 修改/简化 模式的实现。但是,请随时 适应 你需要的模式,不要因为它不存在而阻止你自己 确切地 看起来像描述的访客模式。

    要问的两个问题是

    • “谁负责保存执行操作所需的数据?”

    我通常更喜欢把大部分混凝土放在同一个地方,然后推广到其他地方;这有助于维护(例如添加和删除特性)。尽管访问者模式有助于将操作集中在同一个类中。。。

        4
  •  1
  •   Jay    14 年前

    这听起来像是面向对象编程的基本思想之一。创建一个声明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");
      }
    }
    
        5
  •  1
  •   Cid54    14 年前

    问题是策略模式的教科书范例。将特定的behavoir提取到单独的类中,这些类实现相同的接口(使用doIt()之类的方法)。然后给每个特定类一个对“行为”的引用—您希望它拥有的对象。 2) 你不必重写一个方法(重写方法的危险可能是类爆炸)。

        6
  •  0
  •   crowne    14 年前

    这可以在尝试将一个模式强加给它之前使用普通的旧OO多态性来处理。
    您不必对处理器进行子类化,可以在单个处理器类中重载方法声明,保持方法名称相同,但声明特定类型的参数。

    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将解析与参数类型最匹配的方法,因此如果您有扩展TingB的TingC,那么将调用foo(TingB),直到在Processor类中定义foo(TingC)。


    i、 e.BaseProcessor、TingAProcessor、TingBProcessor。

        7
  •  0
  •   walters    14 年前

    您几乎没有选择:
    *将功能抽象到接口中,并让其他类实现该接口。
    *你可以用这个 Chain of responsibility pattern ( consisting of a source of command objects and a series of processing objects
    . *你也可以用 Strategy design pattern ( algorithms can be selected at runtime )