[英]How to map objects to helper classes using polymorphism?
我想用多态替换switch语句。 让我们以PostOffice
。 该邮局发送Letter
和Package
,这两个都是Mail
子类。 有几种发送不同类型Mail
特定方法,因此有一个LetterService
和PackageService
,它们都是MailService
的
public class PostOffice {
@Inject
private LetterSender letterSender;
@Inject
private PackageSender packageSender;
public void send( Mail mail ) {
if ( mail instanceof Letter ) {
letterSender.send( (Letter) mail );
} else if ( mail instanceof Package ) {
packageSender.send( (Package) mail );
}
}
}
如何避免有条件和instanceof? 有人告诉我可以使用多态性删除它们,但是我仍然不知道如何将正确类型的Mail
“路由”到正确的MailSender
。
根据实际逻辑, LetterSender
和PackageSender
可能确实有两个不同的方法,每个方法都有一个不同的参数。 对于第一个:
public void send(Letter letter);
对于第二个:
public void send(Package letter);
要从多态中受益,您应该定义在这两个类实现的接口中定义的通用方法。 例如 :
public interface MailSender{
void send(Mail mail);
}
但是在Java中,参数不是用于overriding
协变。 因此,您无法通过对Mail
参数进行子类型化来实现该接口。
因此,这意味着您必须在两个Sender类中实现void send(Mail mail)
,例如:
public class LetterSender implements MailSender{
@Override
public void send(Mail mail){
// ...
}
}
public class PackageSender implements MailSender{
@Override
public void send(Mail mail){
// ...
}
}
为此,您应该从较高的角度定义Mail
,在其中定义任何Mail
子类所需的行为/方法。
每个Mail
子类将为其定义实现。
这样,这两个发件人实现就可以处理send(Mail mail)
而无需向下转换参数。
这类问题可以通过几种不同的方式解决。 最简单的版本是责任链:
interface Sender {
boolean canSend(Mail mail);
void send(Mail mail);
}
...
List<Sender> senders;
...
senders.stream()
.filter(s -> s.canSend(mail))
.findAny()
.ifPresentOrElseThrow(
s -> s.send(mail),
() -> new SomethingException()
);
您可以为此使用访客模式。
将接口MailVisitor定义为:
public interface MailVisitor {
void visitLetter(Letter letter);
void visitPackage(Package package);
}
在MailSender中实现此接口:
public class MailSender implement MailVisitor {
@Override
public void visitLetter(Letter letter) {//letter sending goes here}
@Override
public void visitPackage(Package package) {//package sending goes here}
}
现在,在PostOffice类中,让MailSender访问刚刚到达的邮件包:
public class PostOffice {
@Inject
private MailSender mailSender;
public void send(Mail mail) {
mail.visit(mailSender);
}
}
访问方法的实现如下:
public abstract class Mail {
public abstract void visit(MailVisitor visitor);
}
public class Letter extends Mail {
public void visit(MailVisitor visitor) {
visitor.visitLetter(this);
}
}
public class Package extends Mail {
public void visit(MailVisitor visitor) {
visitor.visitPackage(this);
}
}
我花了一段时间才完全了解我第一次遇到它是如何工作的。 但这是一个非常强大的设计模式,可让您消除+ + cast操作的每个实例。
这样的最大优点是,当您定义一个新的Mail子类时,假设是AirMail。 编译器将强制您实现visit(MailVisitor visitor)方法。 这将自动使您在MailVisitor上定义新方法。 这又将使您有义务在MailSender类中实现该新方法。 因此,在定义了能够处理新创建的子类型的逻辑之前,您的代码将无法编译。 而如果您使用了if语句,则可能只是忘记为AirMail添加一个新分支,这将使您的应用程序无法发送任何需要飞机运输的邮件:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.