【问题标题】:Coding tip - intersection types and java enums [closed]编码技巧 - 交集类型和 Java 枚举 [关闭]
【发布时间】:2009-02-22 07:34:38
【问题描述】:

交集类型允许您(有点)做具有继承层次结构的枚举。您不能继承实现,但可以将其委托给辅助类。

enum Foo1 implements Bar {}
enum Foo2 implements Bar {}

class HelperClass {
   static <T extends Enum<T> & Bar> void fooBar(T the enum) {}
}

当您有许多不同的枚举实现某种模式时,这很有用。例如,许多具有父子关系的枚举对。

enum PrimaryColor {Red, Green, Blue;}
enum PastelColor {Pink, HotPink, Rockmelon, SkyBlue, BabyBlue;}

enum TransportMedium {Land, Sea, Air;}
enum Vehicle {Car, Truck, BigBoat, LittleBoat, JetFighter, HotAirBaloon;}

您可以编写通用方法,说“好的,给定一个枚举值,它是一些其他枚举值的父级,子类型的所有可能子枚举中有多少百分比具有此特定父值作为其父值?”,以及拥有所有类型安全并且无需强制转换即可完成。 (例如:“海”是所有可能的车辆的 33%,“绿色”是所有可能的粉彩的 20%。

代码如下所示。请特别注意,“叶子”类本身非常简洁——但泛型类的声明非常丑陋。没关系:你只写一次。一旦有了泛型类,使用它们就很容易了。

下面的帮助类只有一些静态方法。其他方法包括

  • 提供一个返回一个实例 单例,但根据 父母/子女
  • 返回一个实例 对于每个父母/孩子,键入 适当地,并包括一个 每个父枚举

使用第二个选项,“children”对象实际上将位于帮助器内部,因此减少了枚举中所需的代码量。他们都会实例化一个助手,并委派任何困难的事情。

import java.util.EnumSet;

import javax.swing.JComponent;

public class zz extends JComponent {

    public static void main(String[] args) {
        System.out.println(PrimaryColor.Green + " " + ParentUtil.pctOf(PrimaryColor.Green) + "%");
        System.out.println(TransportMedium.Air + " " + ParentUtil.pctOf(TransportMedium.Air) + "%");
    }


}

interface Parent<P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> {
    Class<C> getChildClass();

    EnumSet<C> getChildren();
}

interface Child<P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> {
    Class<P> getParentClass();

    P getParent();
}

enum PrimaryColor implements Parent<PrimaryColor, PastelColor> {
    Red, Green, Blue;

    private EnumSet<PastelColor>    children;

    public Class<PastelColor> getChildClass() {
        return PastelColor.class;
    }

    public EnumSet<PastelColor> getChildren() {
        if(children == null) children=ParentUtil.loadChildrenOf(this);
        return children;
    }
}

enum PastelColor implements Child<PrimaryColor, PastelColor> {
    Pink(PrimaryColor.Red), HotPink(PrimaryColor.Red), //
    Rockmelon(PrimaryColor.Green), //
    SkyBlue(PrimaryColor.Blue), BabyBlue(PrimaryColor.Blue);

    final PrimaryColor  parent;

    private PastelColor(PrimaryColor parent) {
        this.parent = parent;
    }

    public Class<PrimaryColor> getParentClass() {
        return PrimaryColor.class;
    }

    public PrimaryColor getParent() {
        return parent;
    }
}

enum TransportMedium implements Parent<TransportMedium, Vehicle> {
    Land, Sea, Air;

    private EnumSet<Vehicle>    children;

    public Class<Vehicle> getChildClass() {
        return Vehicle.class;
    }

    public EnumSet<Vehicle> getChildren() {
        if(children == null) children=ParentUtil.loadChildrenOf(this);
        return children;
    }
}

enum Vehicle implements Child<TransportMedium, Vehicle> {
    Car(TransportMedium.Land), Truck(TransportMedium.Land), //
    BigBoat(TransportMedium.Sea), LittleBoat(TransportMedium.Sea), //
    JetFighter(TransportMedium.Air), HotAirBaloon(TransportMedium.Air);

    private final TransportMedium   parent;

    private Vehicle(TransportMedium parent) {
        this.parent = parent;
    }

    public Class<TransportMedium> getParentClass() {
        return TransportMedium.class;
    }

    public TransportMedium getParent() {
        return parent;
    }
}

class ParentUtil {
    private ParentUtil(){}
    static <P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> //
    float pctOf(P parent) {
        return (float) parent.getChildren().size() / //
                (float) EnumSet.allOf(parent.getChildClass()).size() //
                * 100f;
    }
    public static <P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> //
    EnumSet<C> loadChildrenOf(P p) {
        EnumSet<C> cc = EnumSet.noneOf(p.getChildClass());
        for(C c: EnumSet.allOf(p.getChildClass())) {
            if(c.getParent() == p) {
                cc.add(c);
            }
        }
        return cc;
    }
}

【问题讨论】:

  • 这不是一个真正的问题,但可能值得重新表述为一个您自己回答的问题,以便我们投票。
  • 这不是一个问题,但我确实认为在 SO 上有一个地方可以做一些事情。我知道 Jeff 不喜欢这个主意,所以你可能会被激怒。
  • 我不得不同意之前的cmets,把这个写成一个问题会更好(记住你可以回答你自己的问题)。
  • 我不同意 SO 是这种事情的地方。这真的是一篇博文。如果它可以写成一个问题,那么就写下这个问题——如果这是一个好的解决方案,它将被投票,如果有更好的解决方案,那么它不会。 -1 恐怕,如果可以的话,我会投票关闭。
  • @Nick Fortescue Jeff 说他想创建一个 SO,让不喜欢写博客的人分享他们的知识。

标签: java generics enums


【解决方案1】:

您可以改用 Commons Enum 实现:

http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/enums/Enum.html

它允许您创建可以被子类化的枚举。

【讨论】:

  • 真正的枚举有一些好处,比如 switch() 的能力。
  • 真正的枚举也是java序列化专门处理的。
【解决方案2】:

这更简单,它做你想做的事吗?

import java.util.*;
interface Tree{
    Tree parent();
    Set<Tree> children();
}
enum PrimaryColor implements Tree {
    Red,Green,Blue;
    @Override public Tree parent() {
        return null;
    }
    @Override public Set<Tree> children() {
        return Collections.unmodifiableSet(children);
    }
    final Set<Tree> children=new LinkedHashSet<Tree>();
}
enum PastelColor implements Tree {
    Pink(PrimaryColor.Red),HotPink(PrimaryColor.Red),Rockmelon(PrimaryColor.Green),SkyBlue(PrimaryColor.Blue),BabyBlue(PrimaryColor.Blue);
    PastelColor(final PrimaryColor primaryColor) {
        this.primaryColor=primaryColor;
        if (primaryColor!=null) primaryColor.children.add(this);
    }
    @Override public Tree parent() {
        return primaryColor;
    }
    @Override public Set<Tree> children() {
        return Collections.emptySet();
    }
    double percent() {
        return primaryColor.children().size()*100./EnumSet.allOf(super.getClass()).size();
    }
    private final PrimaryColor primaryColor;
}
public class Main{
    static double percent(final Tree tree) {
        final Tree parent=tree.parent();
        if (tree instanceof Enum) { return parent.children().size()*100./((Enum)tree).getClass().getEnumConstants().length; }
        else throw new RuntimeException("strange tree!");
    }
    public static void main(String[] args) {
        System.out.println("one way");
        for(PastelColor pastelColor:PastelColor.values())
            System.out.println(pastelColor+" "+pastelColor.percent());
        System.out.println("another way");
        for(PastelColor pastelColor:PastelColor.values())
            System.out.println(pastelColor+" "+percent(pastelColor));
    }
}

【讨论】:

  • 重点是不必将事物转换为 Enum - 在编译时使其类型安全。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-16
  • 2011-05-18
  • 2019-12-29
  • 2021-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多