使用通用父类型输入参数强制执行动态多态调用

发布于 2024-12-24 02:40:41 字数 1817 浏览 2 评论 0原文

我正在尝试使用多态性来根据对象的类启用对对象的不同处理,如下所示:

public class GeneralStuff {
    private int ID;
}

public class IntStuff extends GeneralStuff {
    private int value;

    public void setValue(int v)
    {
        value = v;
    }

    public int getValue()
    {
        return value;
    }
}

public class DoubleStuff extends GeneralStuff {
    private double value;

    public void setValue(double v)
    {
        value = v;
    }

    public double getValue()
    {
        return value;
    }
}

public class ProcessStuff {

    public String process(GeneralStuff gS)
    {
        return doProcess(gS);
    }

    private String doProcess(IntStuff i)
    {
        return String.format("%d", i.getValue());
    }

    private String doProcess(DoubleStuff d)
    {
        return String.format("%f", d.getValue());
    }
}


public class Test {
    public static void main(String[] args)
    {
        IntStuff iS = new IntStuff();
        DoubleStuff dS = new DoubleStuff();
        ProcessStuff pS = new ProcessStuff();

        iS.setValue(5);
        dS.setValue(23.2);

        System.out.println(pS.process(iS));
        System.out.println(pS.process(dS));
    }
}

但是,这不起作用,因为调用 doProcess(gS) 需要一个带有签名 <代码>doProcess(GeneralStuff gS)。

我知道我可以在 ProcessStuff 类中只拥有两个公开的多态处理方法,但实际情况不允许这样做,因为我正在现有库机制的约束下工作;这只是一个为了测试而设计的示例。

当然,我可以将 process(GeneralStuff gS) 定义为

public String process(GeneralStuff gS)
{
    if (gS instanceof IntStuff)
    {
        return doProcess((IntStuff) gS);
    }
    else if (gS instanceof DoubleStuff)
    {
        return doProcess((DoubleStuff) gS);
    }
    return "";
}

有效的,但似乎我不必这样做(另外,编程警察会因为我以这种方式使用 instanceof 而对我进行攻击) )。

有没有一种方法可以更好地强制执行多态调用?

预先感谢您的任何帮助。

I am trying to use polymorphism to enable different processing of an object based on its class, as follows:

public class GeneralStuff {
    private int ID;
}

public class IntStuff extends GeneralStuff {
    private int value;

    public void setValue(int v)
    {
        value = v;
    }

    public int getValue()
    {
        return value;
    }
}

public class DoubleStuff extends GeneralStuff {
    private double value;

    public void setValue(double v)
    {
        value = v;
    }

    public double getValue()
    {
        return value;
    }
}

public class ProcessStuff {

    public String process(GeneralStuff gS)
    {
        return doProcess(gS);
    }

    private String doProcess(IntStuff i)
    {
        return String.format("%d", i.getValue());
    }

    private String doProcess(DoubleStuff d)
    {
        return String.format("%f", d.getValue());
    }
}


public class Test {
    public static void main(String[] args)
    {
        IntStuff iS = new IntStuff();
        DoubleStuff dS = new DoubleStuff();
        ProcessStuff pS = new ProcessStuff();

        iS.setValue(5);
        dS.setValue(23.2);

        System.out.println(pS.process(iS));
        System.out.println(pS.process(dS));
    }
}

This, however, doesn't work, because calling doProcess(gS) expects a method with a signature doProcess(GeneralStuff gS).

I know I could just have two exposed polymorphic process methods in the ProcessStuff class, but the actual situation won't allow it because I'm working within the constraints of an existing library mechanism; this is just a contrived example for testing.

I could, of course, define process(GeneralStuff gS) as

public String process(GeneralStuff gS)
{
    if (gS instanceof IntStuff)
    {
        return doProcess((IntStuff) gS);
    }
    else if (gS instanceof DoubleStuff)
    {
        return doProcess((DoubleStuff) gS);
    }
    return "";
}

which works, but it seems that I shouldn't have to do that (plus, the Programming Police would skewer me for using instanceof in this way).

Is there a way that I can enforce the polymorphic calls in a better way?

Thanks in advance for any help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

毁虫ゝ 2024-12-31 02:40:41

如果不使用反射,您正在寻找的动态调度类型在 Java 中是不可能的。 Java 在编译时根据声明的类型进行链接(因此,即使方法被重载,实际调用的方法也是基于变量的声明类型而不是运行时类型)。

因此,您只能按照您的建议使用instanceof,使用反射,或者将过程方法放在对象本身中(这是“oop”方式,但通常不合适或不建议)。

一种潜在的替代方法是按类创建处理对象的映射,例如:

Map<Class<? extends GeneralStuff>,Processor> processors;

public String process(GeneralStuff stuff)
{
  Processor processor = processors.get(stuff.getClass());
  if (processor != null)
  {
    return processor.process(stuff);
  }
}

public interface Processor
{
  public String process(GeneralStuff stuff);
}

public class IntegerProcessor implements Processor
{
  public String process(GeneralStuff stuff)
  {
    return String.format("%i",((IntegerStuff) stuff).getValue());
  }
}

但是,对于您的特定示例,String.format 将对象作为参数,因此您可以通过在 GeneralStuff 中重写 getValue 和 getFormatString 方法来避免整个问题在具体的子类中。

The type of dynamic dispatch you are looking for is not possible in Java without using reflection. Java does its linking at compile time based on the declared type (so even though a method is overloaded, the actual method invoked is based on the declared type of the variable not the runtime type).

So you are left with either using instanceof as you propose, using reflection, or putting the process methods in the objects themselves (which is the "oop" way to do it, but is often not suitable or advisable).

One potential alternative is to create a map of processing objects by class, eg:

Map<Class<? extends GeneralStuff>,Processor> processors;

public String process(GeneralStuff stuff)
{
  Processor processor = processors.get(stuff.getClass());
  if (processor != null)
  {
    return processor.process(stuff);
  }
}

public interface Processor
{
  public String process(GeneralStuff stuff);
}

public class IntegerProcessor implements Processor
{
  public String process(GeneralStuff stuff)
  {
    return String.format("%i",((IntegerStuff) stuff).getValue());
  }
}

However, for your specific example, String.format takes objects as the parameters, so you could avoid this whole issue by having getValue and getFormatString methods in GeneralStuff which are overriden in the specific subclasses.

蝶…霜飞 2024-12-31 02:40:41

你实际上是在正确的轨道上,在这种情况下你确实需要使用反射。您正在寻找的是双重调度,因为您想要对 stuff 参数的动态类型进行分派。

这种类型的动态切换并不像您想象的那么罕见。例如,请参阅 此 javaworld 提示,它反映了 访客模式

You are actually on the right track, you indeed need to use reflection in this case. What you are looking for is sort of double dispatch, because you want the dispatch to be done on the dynamic type of the stuff parameter.

This type of switching-on-dynamic-type is not as rare as you think. See for example this javaworld tipe, which reflects on the visitor pattern

我为君王 2024-12-31 02:40:41

编译器的抱怨是有充分理由的。无法保证您的 GeneralStuff 对象是 IntStuffDoubleStuff。它可以是普通的 GeneralStuffGeneralStuff 的任何其他扩展,这种情况您也没有在 process 方法中使用 < code>instanceof (除非返回空的String 是所需的行为)。

是否无法将该 process 方法移至 GeneralStuff 类中并在扩展中覆盖它?

另一种可能的解决方案是使用一种复合 ProcessStuff 类,在其中插入 IntStuffProcessDoubleStuffProcess, ... 实例。这些实例中的每一个仍将进行instanceof检查,以决定它们是否可以处理传递给它们的GeneralStuff对象,但这至少比一个大的instanceof构造更具可扩展性/可维护性

The compiler complains for good reason. There is no guarantee that your GeneralStuff object is an IntStuff or a DoubleStuff. It can be a plain GeneralStuff or any other extension of GeneralStuff, which is a case you also did not cover in your process method with the instanceof (unless returning the empty String was the desired behavior).

Is it not possible to move that process method into the GeneralStuff class and override it in the extensions ?

Another possible solution is to have a sort of composite ProcessStuff class in which you plug a IntStuffProcess, DoubleStuffProcess, ... instance . Each of those instances will still have the instanceof check to decide whether they can handle the GeneralStuff object passed to them, but this is at least more scalable/maintainable then one big instanceof construct

一场信仰旅途 2024-12-31 02:40:41

也许,最好在 ProcessStuff 中重载 process 方法:

public class ProcessStuff {

    private String process(IntStuff i) {
        return String.format("%d", i.getValue());
    }

    private String process(DoubleStuff d) {
        return String.format("%f", d.getValue());
    }
}

Perhaps, it's better to have overloaded process method in ProcessStuff:

public class ProcessStuff {

    private String process(IntStuff i) {
        return String.format("%d", i.getValue());
    }

    private String process(DoubleStuff d) {
        return String.format("%f", d.getValue());
    }
}
云柯 2024-12-31 02:40:41

将 GeneralStuff 定义为抽象类,并在继承类中填充 doProcess 方法(抽象)。这样您就可以避免所有有关 instanceof 值等的问题。或者你可以按照 βнɛƨн Ǥʋяʋиɢ 的建议进行操作,但是你仍然必须为每个特定类定义一个重载,而在我的方法中你只需直接调用它。

所以我的建议是:
公共抽象类 GeneralStuff {
私有 int ID;

    public abstract String process();
}

public class IntStuff extends GeneralStuff {
    private int value;

    public void setValue(int v)
    {
        value = v;
    }

    public int getValue()
    {
        return value;
    }

    @override
    public String process(){
        return String.format("%d", getValue());
    }
}

public class DoubleStuff extends GeneralStuff {
    private double value;

    public void setValue(double v)
    {
        value = v;
    }

    public double getValue()
    {
        return value;
    }

    @override
    public String process(){
        return String.format("%f", getValue());
    }
}

public class Test {
    public static void main(String[] args)
    {
        IntStuff iS = new IntStuff();
        DoubleStuff dS = new DoubleStuff();
        ProcessStuff pS = new ProcessStuff();

        iS.setValue(5);
        dS.setValue(23.2);

        System.out.println(iS.process());
        System.out.println(dS.process());
    }
}

Define an GeneralStuff as an abstract class, with a doProcess method (abstract) which is filled in in the inheriting classes. This way you avoid all problems with instanceof values and such. Or you can do what is suggested by βнɛƨн Ǥʋяʋиɢ, but then you still would have to define an overload for each specific class, whereas in mine you just call it directly.

So my suggestion would be:
public abstract class GeneralStuff {
private int ID;

    public abstract String process();
}

public class IntStuff extends GeneralStuff {
    private int value;

    public void setValue(int v)
    {
        value = v;
    }

    public int getValue()
    {
        return value;
    }

    @override
    public String process(){
        return String.format("%d", getValue());
    }
}

public class DoubleStuff extends GeneralStuff {
    private double value;

    public void setValue(double v)
    {
        value = v;
    }

    public double getValue()
    {
        return value;
    }

    @override
    public String process(){
        return String.format("%f", getValue());
    }
}

public class Test {
    public static void main(String[] args)
    {
        IntStuff iS = new IntStuff();
        DoubleStuff dS = new DoubleStuff();
        ProcessStuff pS = new ProcessStuff();

        iS.setValue(5);
        dS.setValue(23.2);

        System.out.println(iS.process());
        System.out.println(dS.process());
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文