Java:如何编写方法来接受子级而不强制转换为父级?

发布于 2024-08-15 03:13:37 字数 554 浏览 11 评论 0原文

不知道如何命名这个...

所以我有 Event 的三个子类:WeightEventTimedEventRepEvent< /代码>。不管怎样,我得到了其中一个孩子的一件物品。现在我想将该子事件发送到另一个对象中的方法,以便它可以使用 getSavedEvents() 方法从中提取数据。该方法仅存在于子级中,因为提取数据特定于事件类型。

我开始

public void setEvent(Event e) {

但将我的子对象转换为 Event (父)对象。

有什么办法可以解决这个问题,编写三种不同的方法。给孩子们每人一份?

public void setEvent(WeightEvent e) {
public void setEvent(TimedEvent e) {
public void setEvent(RepEvent e) {

感谢您的任何建议。

-约翰

Not sure how to title this...

So I've got three child classes of Event: WeightEvent, TimedEvent, RepEvent. Through whatever means, I get an object of one of the children. Now I want to send that child event to a method in another object so it can pull the data from it with the getSavedEvents() method. The method only exists in the children since pulling the data is specific to the type of event.

I started with

public void setEvent(Event e) {

but that cast my child object to an Event (parent) object.

Is there any way around this short of writing three different methods. One each for the children?

public void setEvent(WeightEvent e) {
public void setEvent(TimedEvent e) {
public void setEvent(RepEvent e) {

Thanks for any advice.

-John

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

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

发布评论

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

评论(8

眼角的笑意。 2024-08-22 03:13:37

即使引用被强制转换,它也不会改变实际对象的类型。当您传递引用时,它仍然是对子对象实例的引用。通常这就足够了,如果需要的话,可以在父类型中使用适当的抽象方法。

但是,如果您想要的方法特定于子级的类型,并且您无法提出所有这些方法都可以通用实现的适当抽象,那么您必须使用 instanceof在您的 setEvent 代码中,或者您确实必须重载您的方法...因为您必须根据事件的确切类型调用不同的代码位。

这有点模糊,因为除了几个方法签名之外,我们看不到任何代码。如果您可以向我们提供有关您想要执行的操作的更多详细信息,特别是 setEvent 需要实现的目标以及子类中的不同方法是什么,我们也许能够提供更多帮助。

Even though the reference is cast, it doesn't change the type of the actual object. When you pass the reference on, it will still be a reference to an instance of the child object. Normally this would be enough, with appropriate abstract methods in the parent type if necessary.

However, if the methods you want are specific to the types of the children and you can't come up with an appropriate abstraction which all of them can implement generically, then either you've got to use instanceof within your setEvent code or you do have to overload your method... because you're going to have to call different bits of code depending on the exact type of the event.

This is all a bit vague because we can't see any of your code except a couple of method signatures. If you could give us more details about what you're trying to do, particularly in terms of what setEvent needs to achieve and what the different methods in the child classes are, we may be able to help more.

紫南 2024-08-22 03:13:37

您应该对事件调用针对每种事件类型定义不同的方法,而不是切换类型。这称为模板方法模式。 (顺便说一句,它与 C++ 模板无关)

使用此模式,您的 EventTable 类将变成如下所示:

public class EventTable {
  public void setEvent(Event e) {
    int x = 0;
    columns = e.getFields();
    Event[] savedEvents = e.getSavedEvents();
    for(Event ev : savedEvents) {
      tempdata[x] = ev.getTempData();
      x++;
    }
  }
}

请注意,整个开关已被替换为对 getTempData() 的单个调用。然后这个方法在Event中是抽象的,就像getSavedEvents一样:

public abstract class Event {
  public Date getDate() { return(_date); }
  public abstract Event[] getSavedEvents();
  public abstract int[] getTempData();
  public int[] getFormattedDate() {
    ...

}

然后你在每个子类中定义getTempData()方法。例如:

public class WeightEvent extends Event {
  public int getWeight() { return(_weight); }
  public int getReps() { return(_reps); }
  public int[] getTempData() {
    return new int[]{
      getFormattedDate()[0],
      getWeight(),
      getReps()
    };
  }
}

public class TimedEvent extends Event {
  public String getTimeInHMS() { return(_timeString); }
  public int[] getTempData() {
    return new int[]{
      getFormattedDate()[0],
      getTimeInHMS()
    };
  }
}

public class RepEvent extends Event {
  public int getReps() { return(_reps); }
  public int[] getTempData() {
    return new int[]{
      getFormattedDate()[0],
      getReps()
    };
  }
}

Instead of switching on the type you should call a method on the event that's defined differently for each type of event type. This is called the Template method pattern. (It has nothing to do with C++ templates, BTW)

Using this pattern, your EventTable class becomes something like this:

public class EventTable {
  public void setEvent(Event e) {
    int x = 0;
    columns = e.getFields();
    Event[] savedEvents = e.getSavedEvents();
    for(Event ev : savedEvents) {
      tempdata[x] = ev.getTempData();
      x++;
    }
  }
}

Note that the entire switch has been replaced with a single call to getTempData(). This method is then abstract in Event, just like getSavedEvents:

public abstract class Event {
  public Date getDate() { return(_date); }
  public abstract Event[] getSavedEvents();
  public abstract int[] getTempData();
  public int[] getFormattedDate() {
    ...

}

Then you define the getTempData() method in each subclass. For example:

public class WeightEvent extends Event {
  public int getWeight() { return(_weight); }
  public int getReps() { return(_reps); }
  public int[] getTempData() {
    return new int[]{
      getFormattedDate()[0],
      getWeight(),
      getReps()
    };
  }
}

public class TimedEvent extends Event {
  public String getTimeInHMS() { return(_timeString); }
  public int[] getTempData() {
    return new int[]{
      getFormattedDate()[0],
      getTimeInHMS()
    };
  }
}

public class RepEvent extends Event {
  public int getReps() { return(_reps); }
  public int[] getTempData() {
    return new int[]{
      getFormattedDate()[0],
      getReps()
    };
  }
}
哀由 2024-08-22 03:13:37

您可以使用泛型来做到这一点。

按如下方式定义 Event 类:

public abstract class Event<T extends Event> {
    public abstract void setEvent(T e);
}

这定义了一个期望使用扩展 Event 的任何类型创建的类。

然后在您的子类中,您使用子类作为泛型类型来实现类似的内容:

class WeightEvent extends Event<WeightEvent>
{

    @Override
    public void setEvent(WeightEvent e) {
        ...
    }

}

You could use generics to do this.

Define the Event class as follows:

public abstract class Event<T extends Event> {
    public abstract void setEvent(T e);
}

This defines a class that expects to be created with any type that extends Event.

Then in your child classes you implement something like this using the child class as the generic type:

class WeightEvent extends Event<WeightEvent>
{

    @Override
    public void setEvent(WeightEvent e) {
        ...
    }

}
摘星┃星的人 2024-08-22 03:13:37

我认为您的探针在具有 Event 变量时调用 getSavedEvents()
如果是这样,请向 Event 添加一个抽象的 getSavedEvents() 方法,该方法也必须声明为抽象:

    public abstract class Event {
        public abstract Events getSavedEvents();
        ...
    }

由于 Event 是抽象的,因此您无法创建一个抽象的 getSavedEvents() 方法。它的实例;它必须被子类化才能使用。如果这是一个问题,请在 Event.getSavedEvents() 中抛出异常或为您的应用程序执行任何合理的操作(什么也不做,只是返回 null):

    public class Event {
        public Events getSavedEvents() {
            throw new UnsupportedOperationException("must be called in a child class");
            // OR return null;
        ...
    }

现在您可以调用 getSavedEvents()其他对象中的 方法:

    public class OtherObject {
        private Event event;
        public void setEvent(Event e) {
            event = e;
            ...
            Events events = event.getSavesEvents();

将使用由 e 的真实类实现的方法,例如,如果 eTimedEvent ,该类中的方法将被调用。

I think your probem is calling getSavedEvents() when having an Event variable.
If so, add an abstract getSavedEvents() method to Event, which must also be declared abstract :

    public abstract class Event {
        public abstract Events getSavedEvents();
        ...
    }

since Eventis abstract you can not create an instance of it; it must be subclassed to be used. If that is a problem, throw an Exception or do anything reasonable for your application (nothing at all, just return null) in Event.getSavedEvents():

    public class Event {
        public Events getSavedEvents() {
            throw new UnsupportedOperationException("must be called in a child class");
            // OR return null;
        ...
    }

now you can call the getSavedEvents() method in your other object:

    public class OtherObject {
        private Event event;
        public void setEvent(Event e) {
            event = e;
            ...
            Events events = event.getSavesEvents();

the method implemented by the real class of e will be used, e.g. if e is a TimedEvent, the method in that class will be called.

携余温的黄昏 2024-08-22 03:13:37

您可以将问题抽象出一个接口

interface IEvent
{
    abstract public void doSomething();
}

,然后让所有事件类实现它,例如

class WeightedEvent implements IEvent
{
    public void doSomething()
    {
        // do something
    }
}

然后您只需要一个方法,不需要进行任何类型检查

public void setEvent(IEvent e)
{
    e.doSomething();
}

HTH

You could abstract the problem out behind an interface

interface IEvent
{
    abstract public void doSomething();
}

Then have all your event classes implement it, e.g.

class WeightedEvent implements IEvent
{
    public void doSomething()
    {
        // do something
    }
}

Then you only need a single method and don't need to do any type checking

public void setEvent(IEvent e)
{
    e.doSomething();
}

HTH

も让我眼熟你 2024-08-22 03:13:37

也许您可以使用访问者模式

May be you can use a Visitor pattern.

今天小雨转甜 2024-08-22 03:13:37

使用抽象有助于 getSavedEvents() 方法,因为所有子级都实现该方法。

以下是 setEvent() 的代码:

public class EventTable {
public void setEvent(Event e) {
 int x = 0;
 int type = e.getEventType();

 columns = e.getFields();
 Event[] savedEvents = e.getSavedEvents();
 for(Event ev : savedEvents) {
  tempdata[x][0] = ev.getFormattedDate()[0];
  switch(type) {
   case EVENTTYPE.WEIGHT:
    tempdata[x][1] = ev.getWeight();
    tempdata[x][2] = ev.getReps();
   break;
   case EVENTTYPE.TIMED:
    tempdata[x][1] = ev.getTimeInHMS();
   break;
   case EVENTTYPE.REP:
    tempdata[x][1] = ev.getReps();
   break;
  }
  x++;
 }
}
}

在我将“抽象”添加到 Event 类并定义一个名为 getSavedEvents() 的抽象方法后,此代码即可工作。

下一个问题是 getWeight()、getReps() 和 getTimeInHMS() 方法。它们特定于子事件的类型,并且同样不存在于父事件类中。如果我在 Event 中使它们抽象,现在我必须在每个子项中定义它们,即使 getReps() 没有 TimedEvent 的上下文。

public class Event {
 public Date getDate() { return(_date); }
}
public class WeightEvent extends Event {
 public int getWeight() { return(_weight); }
 public int getReps() { return(_reps); }
}
public class TimedEvent extends Event {
 public String getTimeInHMS() { return(_timeString); }
}
public class RepEvent extends Event {
 public int getReps() { return(_reps); }
}

显然是缩写代码。体重事件具有与其相关的日期、体重和次数。 TimedEvents 具有与其关联的日期和时间长度。重复事件具有与其关联的日期和重复次数。日期方法都在父级中,因为它们在事件中很常见。

如果我不将 getWeight()、getReps() 抽象化,而仅在相关的子级中声明它们,则以下是我在上面复制的 setEvent() 方法中从 EventTable 得到的错误:

EventTable.java:124: cannot find symbol
symbol  : method getWeight()
location: class Event
     tempdata[x][1] = ev.getWeight();

-John

Using abstract helped with the getSavedEvents() method, since all of the children implement that method.

Here's the code for setEvent():

public class EventTable {
public void setEvent(Event e) {
 int x = 0;
 int type = e.getEventType();

 columns = e.getFields();
 Event[] savedEvents = e.getSavedEvents();
 for(Event ev : savedEvents) {
  tempdata[x][0] = ev.getFormattedDate()[0];
  switch(type) {
   case EVENTTYPE.WEIGHT:
    tempdata[x][1] = ev.getWeight();
    tempdata[x][2] = ev.getReps();
   break;
   case EVENTTYPE.TIMED:
    tempdata[x][1] = ev.getTimeInHMS();
   break;
   case EVENTTYPE.REP:
    tempdata[x][1] = ev.getReps();
   break;
  }
  x++;
 }
}
}

This code works after I added "abstract" to the Event class and defined an abstract method called getSavedEvents().

The next problem is the getWeight(), getReps() and getTimeInHMS() methods. They are specific to the type of child event and again don't exist in the parent Event class. If I make them abstract in Event, now I have to define them in each child, even though getReps() has no context for a TimedEvent.

public class Event {
 public Date getDate() { return(_date); }
}
public class WeightEvent extends Event {
 public int getWeight() { return(_weight); }
 public int getReps() { return(_reps); }
}
public class TimedEvent extends Event {
 public String getTimeInHMS() { return(_timeString); }
}
public class RepEvent extends Event {
 public int getReps() { return(_reps); }
}

Abbreviated code, obviously. WeightEvents have a date, weight and reps associated with them. TimedEvents have a date and length of time associated with them. RepEvents have a date and number of reps associated to them. The date methods are all in the parent since they are common across events.

If I don't make getWeight(), getReps() abstract and only declare them in the child where they are relevant, here's the error I get from EventTable in the above copied setEvent() method:

EventTable.java:124: cannot find symbol
symbol  : method getWeight()
location: class Event
     tempdata[x][1] = ev.getWeight();

-John

牛↙奶布丁 2024-08-22 03:13:37

您可以将 Event e 对象强制转换为子类——我认为 Java 中的 instanceof 运算符会对您有所帮助。

You could cast the Event e object to the child classes -- I think the instanceof operator in Java will help you.

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