当我需要更改对象的类型时,有没有一种优雅的方法来重新创建对象?

Is there an elegant way to recreate an object when I need to change its type?

提问人:tmsnvk 提问时间:10/25/2023 最后编辑:Federico klez Cullocatmsnvk 更新时间:10/25/2023 访问量:94

问:

我的一个练习任务是让战士参与任务,以及一个可以计算/过滤/跟踪战士和任务的聚合器类。

我有一个 Fighter 抽象类和三种不同类型的 Fighter(Junior、Medior 和 Senior),它们继承了这个具有许多字段的抽象类。

该方案应该能够将战士提升到更高的军衔——从初级晋升为中级,从中级晋升为高级。我知道在初始化后无法更改对象的类型,但是有没有比我当前的解决方案更好/更优雅的解决方案?即我创建一个更高级别的战斗机的新对象,将原始对象的数据复制到其中,然后删除原始对象。

Java 对象 抽象

评论

6赞 PM 77-1 10/25/2023
为什么不有类变量呢?那么你就不需要子类化了。rank
0赞 Old Dog Programmer 10/26/2023
根据你对答案的回答,我建议你看看装饰器模式

答:

1赞 Basil Bourque 10/25/2023 #1

正如所评论的,听起来排名应该只是你班级的一个属性。Fighter

除非子类具有超出超类的其他数据或行为,否则不应使用继承。

下面是一个完整的示例类。我们定义为具有三个命名常量对象的枚举,即您的三个等级。我们有一个 getter 和一个 setter 方法,供您更改实例上的排名字段。Rank

package work.basil.example;

import java.util.Objects;

public final class Fighter
{
    // Member fields
    private String name;
    private Rank rank;

    enum Rank { JUNIOR, MEDIOR, SENIOR; }

    // Constructor
    public Fighter ( String name ,
                     Rank rank )
    {
        this.name = name;
        this.rank = rank;
    }

    // Accessors
    public String getName ( )
    {
        return name;
    }

    public void setName ( final String name )
    {
       this.name = name ;
    }

    public Rank getRank ( )
    {
        return rank;
    }

    public void setRank ( final Rank rank )
    {
        this.rank = rank;
    }

    // `Object` overrides.
    @Override
    public boolean equals ( Object obj )
    {
        if ( obj == this ) return true;
        if ( obj == null || obj.getClass ( ) != this.getClass ( ) ) return false;
        var that = ( Fighter ) obj;
        return Objects.equals ( this.name , that.name ) &&
                Objects.equals ( this.rank , that.rank );
    }

    @Override
    public int hashCode ( )
    {
        return Objects.hash ( name , rank );
    }

    @Override
    public String toString ( )
    {
        return "Fighter[" +
                "name=" + name + ", " +
                "rank=" + rank + ']';
    }
}

用法:

Fighter alice = new Fighter ( "Alice" , Fighter.Rank.MEDIOR ) ;
alice.setRank( Rank.SENIOR ) ;  // Alice earned a promotion.

评论

1赞 Bohemian 10/25/2023
...他们可以被降级。
0赞 tmsnvk 10/25/2023
嗨,罗勒,谢谢,这是合理的,我想了想。我忘了说,这三种类型的战士可以执行不同的任务,例如初级只能执行任务 A,调解员 A 和 B,高级战士 A、B、C。MissionTypes 存储在枚举中。目前,这些类型存储在每个战斗机类的静态变量中。如果我按照您的示例进行操作,则必须存储一个列表并在构造函数中设置 MissionTypes。这听起来似乎很合理,但是,我被警告不要在构造函数中使用过多的逻辑。您对此有何看法?干杯,T
0赞 Basil Bourque 10/30/2023
@tmsnvk构造函数确实应该保持简单。但是,如果输入的数据验证可以保持简单(如果不简单,请使用构建器),则对于构造函数来说是合法的函数。验证分配的任务时,请使用详尽的 switch 语句,每个级别都有一个大小写。如果该等级的任务是错误的,则抛出非法参数异常。提示:您可以使用来保留一组适合每个等级的任务;叫。EnumSetSet#contains
0赞 tmsnvk 10/31/2023
感谢@BasilBourque的详细解释,非常感谢!