为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用多态将对象映射到辅助类?

如何使用多态将对象映射到辅助类?

largeQ 2021-09-12 17:24:22
我想用多态替换 switch 语句。让我们以 a 为例PostOffice。此邮局发送Letter's 和Package's,它们都是 的子类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 );        }    }}如何避免条件和实例?有人告诉我,您可以使用多态删除这些,但我仍然不明白如何将正确的类型“路由”Mail到正确的MailSender.
查看完整描述

3 回答

?
慕标琳琳

TA贡献1830条经验 获得超9个赞

根据实际逻辑,LetterSender并且PackageSender确实可能有两个不同的方法,每个方法都有一个不同的参数。对于第一个:


 public void send(Letter letter);

对于第二个:


 public void send(Package letter);

为了从多态中受益,您应该定义在这两个类实现的接口中定义的公共方法。例如 :


public interface MailSender{

   void send(Mail mail);

}

但是在 Java 中,参数对于overriding. 所以你不能通过对Mail参数进行子类型化来实现接口。

所以这意味着你必须void send(Mail mail)在两个 Sender 类中实现,例如:


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)在不需要向下转换参数的情况下进行处理。


查看完整回答
反对 回复 2021-09-12
?
Helenr

TA贡献1780条经验 获得超3个赞

您可以为此使用访问者模式。


定义一个接口 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);

    }

}

当我第一次遇到它时,我花了一段时间才完全掌握它是如何工作的。但它是一种非常强大的设计模式,它允许您消除每个 instanceof + cast 操作。


这样做的最大优点是当您定义一个新的 Mail 子类时,比如说 AirMail。编译器将强制您实现visit(MailVisitorvisitor) 方法。这将自动让您在 MailVisitor 上定义一个新方法。这将反过来迫使您在 MailSender 类中实现该新方法。因此,除非您定义了能够处理新创建的子类型的逻辑,否则您的代码将无法编译。而如果您使用了 if 语句,您可能只是忘记为 AirMail 添加一个新分支,这将使您的应用程序无法发送任何需要飞机运输的邮件:)


查看完整回答
反对 回复 2021-09-12
?
白猪掌柜的

TA贡献1893条经验 获得超10个赞

这类问题可以通过几种不同的方式解决。最简单的版本是责任链:


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()

    );


查看完整回答
反对 回复 2021-09-12
  • 3 回答
  • 0 关注
  • 147 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信