每次使用google instanceof和cast进行搜索时,我总是会看到回答,避免使用X模式。
我有一个示例,其中看不到我认为可以使用的任何模式。
我们有2类:订单和付款(现金付款和卡付款)。
CashPayment具有1个名为amount
的属性和一个已实现的方法pay
。
CardPayment具有1个名为cardNumber
的属性和一个已实现的pay
,该属性调用了第三方API。
现在说您想撰写有关订单的视图,有人会如何避免在此处使用instanceof或强制转换来显示付款明细?
使用instanceof可以做到:
order = new Order(...);
order.checkout(aPayment);
Payment Details (Cash):
Type: (instanceof CashPayment ? "Cash") or order.payment().type();
Amount: ((CashPayment) order.payment()).amount();
Payment Details (Card):
Type: (instanceof CardPayment ? "Card") or order.payment().type();
Card Number: ((CardPayment) order.payment()).cardNumber();
问题:我们真的可以避免执行instanceof和cast吗?如果是的话,我们如何实现这一“ OO路”?如果没有,我认为这是有效的情况之一?
IMO,我们可以避免instanceof / casting并赞成使用重写的方法,但是,如果您想知道一个具体的对象,那是不可避免的。
编辑:
我正在尝试编写域模型,这意味着它与基础架构和特定于应用程序的内容无关。
想象一下,我们需要通过OrderRepository保存Order,并且Payment具有自己的表。像这样不是很丑吗?
class OrderRepository {
public function save(Order order) {
// Insert into order query here...
// Insert into orderItems query here...
// Insert payment into its table
queryBuilder
.table(order.payment().tableName())
.insert([
order.payment().columnName() => order.payment().value()
]);
}
}
答案 0 :(得分:0)
显而易见的面向对象的解决方案是在display()
上添加Payment
方法。
通常来说,/ casting的实例是令人头疼的,因为它通常表示次优的设计。唯一允许的时间是类型系统的功能不足以表达某些内容。我在Java中遇到了几种情况,没有更好的解决方案(主要是因为Java中没有只读集合,因此泛型参数是不变的),而Scala或Haskell中都没有。
答案 1 :(得分:0)
您可以通过继承使用组成。
也许是这样的:
public class Payment
{
private CardPaymentDetail _cardPaymentDetail;
public PaymentType Type { get; private set; }
public decimal Amount { get; }
private Payment(decimal amount)
{
// > 0 guard
Amount = amount;
}
private Payment(decimal amount, CardPaymentDetail cardPayment)
: this(amout)
{
// null guard
CardPayment = cardPayment;
}
public CardPaymentDetail CardPayment
{
get
{
if (Type != PaymentType.Card)
{
throw new InvalidOperationException("This is not a card payment.");
}
return _cardPaymentDetail;
}
}
}
恕我直言,持久性也可能更容易。同样,我还使用了等同于Unknown
的付款方式作为默认付款方式,然后使用一种方法来指定付款方式:AsCard(CardPaymentDetail cardPayment) { }
。
答案 2 :(得分:0)
如果您绝对希望将操作与对象本身分开(例如,保持关注点分离),但是操作与子类详细信息紧密耦合,那么您只有两种选择。
您要么需要重新考虑模型并找到同构的抽象,这可以是允许您以相同方式处理各种类型的任何方法。
例如
Payment Details:
Type: {{payment.type}}
{{for attr in payment.attributes}}
{{attr.name}}: {{attr.value}}
{{/}}
或者您需要执行某种类型匹配,无论您使用的是访客模式,模式匹配,instanceof
等。
interface IPaymentVisitor {
public void visit(CashPayment payment);
public void visit(CardPayment payment);
}
class PaymentRenderer implements IPaymentVisitor ...
class CashPayment extends Payment {
...
public void visit(IPaymentVisitor visitor) {
visitor.visit(this);
}
}
var renderer = new PaymentRenderer(outputStream);
payment.accept(renderer);