【问题标题】:Java constructor overloading ambiguityJava构造函数重载歧义
【发布时间】:2013-06-07 15:46:25
【问题描述】:

如何解决以下constructor overloading问题?这是一个面试问题,但我很想知道解决方案。

class Player
{
    int nationalRank;
    int internationalRank;
    String name;

    Player(String name, int nationalRank)
    {
        this.name= name;
        this.nationalRank = nationalRank;
        this.internationalRank=0;
    }

    Player(String name, int internationalRank)
    {
        this.name= name;
        this.nationalRank = 0;
        this.internationalRank=internationalRank;
    }
}

这里,编译器会报错,因为两个构造函数的参数类型相同。但从逻辑上讲,两者是不同的。如何在不添加任何额外参数的情况下解决此问题?有没有专门针对这个的设计模式?

【问题讨论】:

  • 给每个选项一个有意义的名字的静态工厂方法怎么样?
  • 他们有相同的原型,不改变参数我看不出你怎么能这样做,你可以做什么?可以创建子类吗?
  • @Djon 是的,我想我可以创建子类。任何解决方案都是首选。
  • 一个简单但不明确的解决方案是更改参数(int,String)(String,int) 的顺序。
  • @TheNewIdiot 是的,但我认为这个解决方案在实际项目中不会受到青睐。

标签: java constructor overloading


【解决方案1】:
class Player
{
    int nationalRank;
    int internationalRank;
    String name;

    private Player(){}

    public static Builder builder() 
    {
       return new Builder();
    }

    public static class Builder
    {
      int nationalRank = -1;
      int internationalRank = -1;
      String name;

      public Builder nationalRank(int nationalRank)
      {
        this.nationalRank = nationalRank;
        return this;
      }

      public Builder internationalRank(int internationalRank)
      {
        this.internationalRank = internationalRank;
        return this;
      }

      public Builder name(String name)
      {
        this.name = name;
        return this;
      }

      public Player build()
      {
        if (nationalRank == -1 && internationalRank = -1)
          throw new IllegalStateException("both ranks haven't been initialized");
        if (null == name)
          throw new IllegalStateException("name hasn't been initialized");
        Player result = new Player();
        result.nationalRank = this.nationalRank;
        result.internationalRank = this.internationalRank;
        result.name = this.name;
        return result;
      }
    }
}

用法:

Player player = Player.builder().name("John").internationalRank(522).build();

【讨论】:

【解决方案2】:

您有多种选择。

最简单的就是像这样添加工厂方法:

public class Player
{
  private int nationalRank;
  private int internationalRank;
  private String name;

  private Player()
  {
  }

  public static Player newNationalPlayer(String name, int nationalRank)
  {
    Player nationalPlayer = new Player();

    nationalPlayer.name= name;
    nationalPlayer.nationalRank = nationalRank;
    nationalPlayer.internationalRank = 0;

    return nationalPlayer;
  }

  public static Player newInternationalPlayer(String name, int internationalRank)
  {
    Player internationalPlayer = new Player();

    internationalPlayer.name= name;
    internationalPlayer.nationalRank = 0;
    internationalPlayer.internationalRank = internationalRank;

    return internationalPlayer;
  }

  ...
}

但是,这会留下一个不太好用的未使用变量。更好的解决方案是添加 PlayerType 枚举:

public enum PlayerType
{
  NATIONAL,
  INTERNATIONAL
}

public class Player
{
  private int rank;
  private String name;
  private PlayerType type;

  public Player(String name, PlayerType type, int rank)
  {
    this.name= name;
    this.type = type;
    this.rank = rank;
  }

  ...
}

哪个最好取决于具体的用例。

【讨论】:

    【解决方案3】:

    只需反转其中一个构造函数的参数,你就可以开始了....我做出这个回答时认为这是一个面试问题......也许面试官有这个想法......

     class Player
        {
            int nationalRank;
            int internationalRank;
            String name;
    
            Player(String name, int nationalRank)
            {
                this.name= name;
                this.nationalRank = nationalRank;
                this.internationalRank=0;
            }
    
            Player( int internationalRank,String name)
            {
                this.name= name;
                this.nationalRank = 0;
                this.internationalRank=internationalRank;
            }
        }
    

    【讨论】:

    • 哦,我知道你在那里做了什么。
    • 这是一个很好的技巧。但也许我可以得到更通用的解决方案
    • 是的,但他回答了这个问题,我真的没有看到它的到来。
    • @SamDufel 但在面试中,他们会检查这个人是否有这种能力......也......这是一个面试问题......不是一个真正的项目......如果它是一个真正的项目,我们不受限制
    【解决方案4】:

    正如评论所建议的,只需使用静态工厂方法。事实上,这个解决方案比这更进一步,它使用了一个构建器。您会注意到一个明显的优势:所有实例变量现在都是最终变量。

    public class Player
    {
        private final String name;
        private final int nationalRank;
        private final int internationalRank;
    
        // Constructor becomes private
        private Player(final Builder builder)
        {
            name = builder.name;
            nationalRank = builder.nationalRank;
            internationalRank = builder.internationalRank;
        }
    
        public static Builder withName(final String name)
        {
            return new Builder(name);
        }
    
        // Inner builder class
        public static class Builder
        {
            private final String name;
            private int nationalRank;
            private int internationalRank;
    
            private Builder(final String name)
            {
                this.name = name;
            }
    
            public Builder withNationalRank(int rank)
            {
                nationalRank = rank;
                return this;
            }
    
            public Builder withInternationalRank(int rank)
            {
                internationationalRank = rank;
                return this;
            }
    
            public Player build()
            {
                return new Player(this);
            }
        }
    }
    

    用法:

    Player player1 = Player.withName("foo").withNationalRank(1).build();
    // etc
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-24
      • 1970-01-01
      相关资源
      最近更新 更多