如何创建具有关联值(如 Swift 枚举)的 Java 枚举?

How can I create a Java enum with associated values like Swift enum?

编辑: 明确地说,我不是在问如何在 java 中进行枚举。我问的是 java 中是否有与枚举中的 Swifts 关联值互补的内容。这不仅仅是我如何在枚举上存储值。看一下我提供的示例,您会发现不同之处。

所以一位 iOS 开发人员向我展示了他使用 swifts 枚举相关值的架构。这个概念对我来说似乎很有趣,作为一名 android 开发人员,我很好奇它是否可以在 java 中使用而不过于冗长。 Java 枚举的等价物是什么?还是不可能?

这是我所说的关联值的一个例子。它来自 apple docs.

enum Barcode {
    case UPCA(Int, Int, Int, Int)
    case QRCode(String)
}

// Instantiated
var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
// or
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")


switch productBarcode {
case .UPCA(let numberSystem, let manufacturer, let product, let check):
    println("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
case .QRCode(let productCode):
    println("QR code: \(productCode).")
}

对于使用 Java 枚举的我来说,这是不可能的。

要接近您发布的代码段,您会很冗长,正如您已经假设的那样。

枚举

enum BarcodeType {
    UPCA,
    QRCode,
    UNDEFINED;
}

工厂class

abstract class Barcode {

    abstract public BarcodeType getType();

    public static final Barcode newUPCA(int numberSystem, int manufacturer, int product, int check) {
        return new BarcodeUPCA(numberSystem, manufacturer, product, check);
    }

    public static final Barcode newQRCode(String productCode) {
        return new BarcodeQRCode(productCode);
    }
}

具体实现UPCA

class BarcodeUPCA extends Barcode {
    private final int numberSystem;
    private final int manufacturer;
    private final int product;
    private final int check;

    public BarcodeUPCA(int numberSystem, int manufacturer, int product, int check) {
        this.numberSystem = numberSystem;
        this.manufacturer = manufacturer;
        this.product = product;
        this.check = check;
    }

    public int getNumberSystem() {
        return numberSystem;
    }

    public int getManufacturer() {
        return manufacturer;
    }

    public int getProduct() {
        return product;
    }

    public int getCheck() {
        return check;
    }

    @Override
    public BarcodeType getType() {
        return BarcodeType.UPCA;
    }
}

QRCode的具体实现

class BarcodeQRCode extends Barcode {

    private final String productCode;

    public BarcodeQRCode(String productCode) {
        this.productCode = productCode;
    }

    public String getProductCode() {
        return productCode;
    }

    @Override
    public BarcodeType getType() {
        return BarcodeType.QRCode;
    }
}

演示应用程序

public class BarcodeMain {

    public static void main(String[] args) throws Exception {
        List<Barcode> barcodes = new ArrayList<>();
        barcodes.add(Barcode.newUPCA(8, 85909, 51226, 3));
        barcodes.add(Barcode.newQRCode("foobar"));

        for (Barcode barcode : barcodes) {
            switch (barcode.getType()) {
                case UPCA: {
                    BarcodeUPCA b = (BarcodeUPCA) barcode;
                    System.out.printf("UPC-A: %d, %d, %d, %d%n",
                            b.getNumberSystem(),
                            b.getManufacturer(),
                            b.getProduct(),
                            b.getCheck()
                    );
                    break;
                }
                case QRCode: {
                    BarcodeQRCode b = (BarcodeQRCode) barcode;
                    System.out.printf("QR code: %s%n", b.getProductCode());
                    break;
                }
                default:
                    System.err.println("unhandled type: " + barcode.getType());
            }
        }
}

输出

UPC-A: 8, 85909, 51226, 3
QR code: foobar

我也被这个问题困扰过,想出了以下解决方案。值得注意的是,我什至不使用枚举,因为 Java 的枚举不太适合这项任务。重要的是,您需要对案例采取类似 switch 的行为,并在每个案例中提供相关值。

类枚举类型

public abstract class Barcode
{
    private Barcode() {}

    void caseUPCA(IntFunction<IntFunction<IntFunction<IntConsumer>>> action) {}
    void caseQRCode(Consumer<String> action) {}

    static Barcode UPCA(int numberSystem, int manufacturer, int product, int check)
    {
        return new Barcode()
        {
            @Override public void caseUPCA(IntFunction<IntFunction<IntFunction<IntConsumer>>> action)
            {
                action.apply(numberSystem).apply(manufacturer).apply(product).accept(check);
            }
        };
    }

    static Barcode QRCode(String text)
    {
        return new Barcode()
        {
            @Override public void caseQRCode(Consumer<String> action)
            {
                action.accept(text);
            }
        };
    }
}

演示应用程序

public class BarcodeMain
{
    public static void main(String[] args) throws Exception
    {
        List<Barcode> barcodes = new ArrayList<>();
        barcodes.add(Barcode.UPCA(8, 85909, 51226, 3));
        barcodes.add(Barcode.QRCode("foobar"));

        for(Barcode barcode: barcodes)
        {
            barcode.caseUPCA(numberSystem -> manufacturer -> product -> check ->
                System.out.printf("UPC-A: %d, %d, %d, %d%n", numberSystem, manufacturer, product, check));
            barcode.caseQRCode(productCode ->
                System.out.printf("QR code: %s%n", productCode));
        }
    }
}

输出

UPC-A: 8, 85909, 51226, 3
QR code: foobar

优点

  • 实现代码比基于枚举的解决方案少得多
  • 与基于枚举的解决方案相比,使用站点的代码更少

缺点

  • Barcode 实现中有很多笨拙的嵌套。只是 Java 丑。
  • 您不能从 switch case 操作中抛出异常。
  • UPCA 实现中的尖括号盲目性,因为有很多参数。为防止这种情况泄漏到 API,您可以声明一个 public interface UPCAConsumer extends IntFunction<IntFunction<IntFunction<IntConsumer>>> {},并使用 UPCAConsumer 作为 caseUPCA(action) 参数类型。