如何在 Java 中表示不相交的联合类型?
How do I represent disjoint union types in Java?
假设我在系统中有一个数据定义:
A PaymentMethod
is one of Cash
or CreditCard(String accountNum)
.
操作此(不相交联合)数据的一种方法是使用访问者模式:
interface IPaymentMethod {
<R> R visit(IPaymentMethod.IVisitor<R> visitor);
interface IVisitor<R> {
R visitCash();
R visitCreditCard(String accountNum);
}
}
class Cash implements IPaymentMethod {
<R> R visit(IPaymentMethod.IVisitor<R> visitor) {
return visitor.visitCash();
}
}
class CreditCard implements IPaymentMethod {
String accountNum;
// constructor here
<R> R visit(IPaymentMethod.IVisitor<R> visitor) {
return visitor.visitCreditCard(this.accountNum);
}
}
除了实现和使用访问者的冗长之外,它对扩展过于开放:如果我希望我的图书馆的消费者产生 IPaymentMethod
s,我只希望 Cash
或 CreditCard
s 将被 returned。但是,他们可能 return 他们自己的实现,这没有任何意义。这里是否有另一种模式可以更好地表示此数据并可以保证我只处理 Cash
和 CreditCard
s? (当然,如果不是为了String accountNum
,一个enum就好了。)
/**
* A PaymentMethod is one of Cash or CreditCard(String accountNum).
*/
public abstract class PaymentMethod {
private PaymentMethod() {}
/**
* Creates a Cash payment method.
*/
public static PaymentMethod makeCash() {
return new Cash();
}
/**
* Creates a CreditCard payment method with an account number.
*/
public static PaymentMethod makeCreditCard(String accountNum) {
return new CreditCard(accountNum);
}
public abstract <R> R visit(IVisitor<R> visitor);
public interface IVisitor<R> {
R visitCash();
R visitCreditCard(String accountNum);
}
private static class Cash extends PaymentMethod {
@Override
public <R> R visit(IVisitor<R> visitor) {
return visitor.visitCash();
}
}
private static class CreditCard extends PaymentMethod {
private final String accountNum;
private CreditCard(String accountNum) {
this.accountNum = accountNum;
}
@Override
public <R> R visit(IVisitor<R> visitor) {
return visitor.visitCreditCard(this.accountNum);
}
}
}
此解决方案保留访问者模式来对 PaymentMethod 的每个子class 执行操作,但使用工厂模式来创建这些子class。私有 PaymentMethod 构造函数阻止 class 的外部扩展,从而关闭联合。可以放宽访问修饰符(即使用包私有构造函数)以仅允许在包内进行扩展并允许提取现金和信用卡 classes.
它很冗长,是的,但它似乎是 Java <17 的最佳解决方案(请参阅 David Conrad 关于密封 classes 的评论)。
假设我在系统中有一个数据定义:
A
PaymentMethod
is one ofCash
orCreditCard(String accountNum)
.
操作此(不相交联合)数据的一种方法是使用访问者模式:
interface IPaymentMethod {
<R> R visit(IPaymentMethod.IVisitor<R> visitor);
interface IVisitor<R> {
R visitCash();
R visitCreditCard(String accountNum);
}
}
class Cash implements IPaymentMethod {
<R> R visit(IPaymentMethod.IVisitor<R> visitor) {
return visitor.visitCash();
}
}
class CreditCard implements IPaymentMethod {
String accountNum;
// constructor here
<R> R visit(IPaymentMethod.IVisitor<R> visitor) {
return visitor.visitCreditCard(this.accountNum);
}
}
除了实现和使用访问者的冗长之外,它对扩展过于开放:如果我希望我的图书馆的消费者产生 IPaymentMethod
s,我只希望 Cash
或 CreditCard
s 将被 returned。但是,他们可能 return 他们自己的实现,这没有任何意义。这里是否有另一种模式可以更好地表示此数据并可以保证我只处理 Cash
和 CreditCard
s? (当然,如果不是为了String accountNum
,一个enum就好了。)
/**
* A PaymentMethod is one of Cash or CreditCard(String accountNum).
*/
public abstract class PaymentMethod {
private PaymentMethod() {}
/**
* Creates a Cash payment method.
*/
public static PaymentMethod makeCash() {
return new Cash();
}
/**
* Creates a CreditCard payment method with an account number.
*/
public static PaymentMethod makeCreditCard(String accountNum) {
return new CreditCard(accountNum);
}
public abstract <R> R visit(IVisitor<R> visitor);
public interface IVisitor<R> {
R visitCash();
R visitCreditCard(String accountNum);
}
private static class Cash extends PaymentMethod {
@Override
public <R> R visit(IVisitor<R> visitor) {
return visitor.visitCash();
}
}
private static class CreditCard extends PaymentMethod {
private final String accountNum;
private CreditCard(String accountNum) {
this.accountNum = accountNum;
}
@Override
public <R> R visit(IVisitor<R> visitor) {
return visitor.visitCreditCard(this.accountNum);
}
}
}
此解决方案保留访问者模式来对 PaymentMethod 的每个子class 执行操作,但使用工厂模式来创建这些子class。私有 PaymentMethod 构造函数阻止 class 的外部扩展,从而关闭联合。可以放宽访问修饰符(即使用包私有构造函数)以仅允许在包内进行扩展并允许提取现金和信用卡 classes.
它很冗长,是的,但它似乎是 Java <17 的最佳解决方案(请参阅 David Conrad 关于密封 classes 的评论)。