【问题标题】:Class Design advise (Implement with Java) - enum + inheritance类设计建议(用 Java 实现)- 枚举 + 继承
【发布时间】:2017-10-02 14:40:38
【问题描述】:

我有一个包含以下类的设计:

public class Book {
  protected BookColorType color;
  public Book (BookColorType color) {
    ...
  }
}

public enum BookColorType {
  BLACK, WHITE
}

public enum ColorBookColorType {
  BLACK, WHITE, RED, BLUE, GREEN
}

public class ColorBook extends Book {
  protected ColorBookColorType color;
  public ColorBook(ColorBookColorType color) {
    // this will cause error has ColorBookColorType is not the same type as BookColorType
  }
}

如何使用 Java 和更好的类设计来实现上述功能? 重点是 Book 应该只与 BookColorType 相关联,而 ColorBook(是一本书),并且只与 ColorBookColorType 相关联(BLACK 和 WHITE 重复)。

请指教,谢谢。

【问题讨论】:

  • 在这种情况下,是什么让ColorBook 成为Book?您认为目前的实施有什么可疑之处?
  • 您已经提供了 Java 实现,那么您的问题是什么?至于设计:最好让Book 是一个接口或抽象类和另一个实现/子类,如NonColoredBook。我的问题是我无法想象这里的颜色会表示什么,即黑书与白书有何不同?需要详细说明吗?
  • 对我来说,这听起来像是一个糟糕的设计和滥用继承。
  • 我没有在这里展示课程的所有内容。我的主要问题是我是否有这样的类继承,并且它们都有一个字段“颜色”,当颜色在这里有某种关系时。我会寻找更好的设计。

标签: java class inheritance enums


【解决方案1】:

如果Book 的每种类型都必须有自己的颜色Type 枚举,则让每个类只知道它需要的颜色类型。
因此,不要将 BookColorType color; 设为继承自 Book 类的字段,而是将其设为私有字段,并使 ColorBook 拥有自己的私有颜色类型字段:ColorBookColorType color;

此外,如果从两个枚举类中检索一个值(字符串或公共枚举值或其他值)以使它们以某种方式互操作是有意义的,那么您可以让它们实现特定的接口。

【讨论】:

    【解决方案2】:

    这是一个想法:

    • 您可以让两个枚举都实现一个接口,例如BookColorType
    • 然后,您可以将当前的 BookColorType 枚举重命名为 BWBookColorType
    • 您的Book 超类保留构造函数并将BookColorType 对象作为参数
    • 您的ColorBook 的构造函数调用super(...)
    • 如果参数的实际类型不是ColorBookColorType,则它可以抛出IllegalArgumentException
    • 请注意,您的ColorBook 类不会有自己的字段,而是会重用Book 的字段,该字段的类型为BookColorType(接口的类型)

    示例

    public class Book {
        protected BookColorType color;
    
        public Book(BookColorType color) {
    
        }
    }
    
    public interface BookColorType {}
    
    public enum BWBookColorType implements BookColorType {
        BLACK, WHITE
    }
    
    public enum ColorBookColorType implements BookColorType {
        BLACK, WHITE, RED, BLUE, GREEN
    }
    
    public class ColorBook extends Book {
    
        public ColorBook(BookColorType color) {
            super(color); // need to be 1st line
            if (!(color instanceof ColorBookColorType)) {
                throw new IllegalArgumentException("Only colored books!");
            }
        }
    
    }
    

    【讨论】:

    • (color instanceof ColorBookColorType) 这个挺难看的,可以换个接口解决。
    • @Oleg 我对你的评论有点困惑......你能详细说明为什么类型检查很难看,或者特别是关于“用另一个接口解决”的部分吗?
    • 有另一个接口interface BookColorTypeColor extends BookColorType{} color enum 可以实现它并且colorbook构造函数将它作为参数,这样你就不需要任何类型检查。至于为什么真的很丑?!类型检查是最后的手段,如果你不介意它们,只需使用 Object 来检查所有内容并用类型检查填充你的代码。
    • @Oleg 在我看来类型检查可能是必要的,我仍然认为他们在这种情况下。如果您正在重载构造函数(即在子类中采用不同的类型参数),您仍然需要调用超级构造函数,但您将没有可以调用它的实际类型。这是一个陷阱 22,因为在方法/构造函数参数参数化中没有协变,只有在返回类型中。
    • @user6539552 不客气!请继续关注,因为有人可能还有更好的主意。
    【解决方案3】:

    关键是用强类型来表达约束,而不是像 instanceof 这样惯用的运行时检查。

    public interface Book {
      BookColor getColor();
    }
    
    public interface BookColor {
    
    }
    
    public enum MonoChrome implements BookColor {
      BLACK, WHITE
    }
    
    public enum Colorful implements BookColor {
      RED, BLUE, GREEN
    }
    
    public final class ColorBook implements Book {
        private final Color color;
    
        public ColorBook(final BookColor color) {
          super();
          this.color = Objects.requireNonNull(color);
        }
    }
    
    public final class MonoChromeBook implements Book {
        private final Color color;
    
        public ColorBook(final MonoChrome color) {
          super();
          this.color = Objects.requireNonNull(color);
        }
    }
    

    这样,ColorBook 可以同时使用 MonoChrome 和 ColorFul 作为颜色。 MonoChromeBook 只接受 MonoChrome 颜色。

    【讨论】:

      【解决方案4】:

      基于@Mena 的帖子,我将使用泛型来强制颜色类型:

      public interface BookColorType {}
      
      public class Book<C extends BookColorType> {
          protected C color;
      
          public Book(C color) {
      
          }
      }
      
      public enum BWBookColorType implements BookColorType {
          BLACK, WHITE
      }
      
      public enum ColorBookColorType implements BookColorType {
          BLACK, WHITE, RED, BLUE, GREEN
      }
      
      public class ColorBook extends Book<ColorBookColorType> {
          public ColorBook(ColorBookColorType color) {
              super(color);
          }
      }
      
      public class BWBook extends Book<BWBookColorType> {
          public BWBook(BWBookColorType color) {
              super(color);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-29
        • 2010-10-19
        相关资源
        最近更新 更多