Java 我应该使用这样的接口吗?

Java 我应该使用这样的接口吗?,java,oop,inheritance,interface,Java,Oop,Inheritance,Interface,我发现自己处于这样一种情况:我想使用接口,但我在猜测自己 我正在写一份申请书来处理保险申请。有一个应用程序对象,它保存有关保险应用程序的所有数据。这包括有关被保险人、将拥有保险单的实体以及将支付保险范围的实体的数据 我使用实体一词是因为保单可以由个人或信托拥有(或支付)。我知道当我与所有者或付款人打交道时,但我不一定知道该所有者或付款人是个人还是信托。我最初创建所有者界面是为了减少基于casting和instanceof的逻辑。我原打算钉在付款人界面上,但现在我在猜测自己 这可能是你现在需要知道

我发现自己处于这样一种情况:我想使用接口,但我在猜测自己

我正在写一份申请书来处理保险申请。有一个应用程序对象,它保存有关保险应用程序的所有数据。这包括有关被保险人、将拥有保险单的实体以及将支付保险范围的实体的数据

我使用实体一词是因为保单可以由个人或信托拥有(或支付)。我知道当我与所有者或付款人打交道时,但我不一定知道该所有者或付款人是个人还是信托。我最初创建所有者界面是为了减少基于casting和instanceof的逻辑。我原打算钉在付款人界面上,但现在我在猜测自己

这可能是你现在需要知道的全部。下面是一些代码:

public class Application{
    private Person insured;
    private Owner owner;
    private Payor payor;

    ...

}

public interface Owner{
    public void setAddress(Address address);
    public Address getAddress();

    public void setId(String id);
    public String getId();

    public void setPIN(String pin);
    public String getPIN();
}

public interface Payor{
    public void setAccount(Account account);
    public Account getAccount();
}

public class Person implements Owner, Payor{
    ...
}

public class Trust implements Owner, Payor{
    ...
}
我是走在正确的道路上,还是应该采取不同的做法?让我停顿的是,并不是每个人都是所有者或付款人

当我进一步思考时,我觉得所有者和付款人与其说是“行为”,不如说是“分类”。这是否使我在这里使用的接口不正确?如果是这样,您是否有其他解决方案的建议?最好是允许我继续透明地使用个人和信托作为所有者和付款人

我担心的部分原因是不太熟悉的开发人员将一个人与下面这样的所有者混淆

Application app = new Application();
Person timmy = new Person();
Owner smithFamilyTrust = new Trust();
Payor steve = new Person();

app.setInsured(timmy);
app.setOwner(smithFamilyTrust);
app.setPayor(steve);

...

//this would run, but would be wrong
if(timmy instanceof Owner){
   //Do Owner Stuff.
}

//this would run, and be correct
Owner owner = app.getOwner();
//Do Owner Stuff
编辑以澄清“所有者资料”

在这一点上,“所有者的东西”很简单。获取/设置所有者的id、PIN或地址:

//I want this
app.getOwner().getId();
app.getOwner().getPIN();
app.getOwner().getAddress();

//I don't want this
if(app.getOwner() instanceof Person){
    Person owner = app.getOwner();
    owner.getId();
    owner.getPIN();
    owner.getAddress();
} else if(app.getOwner() instanceof Trust){
    Trust owner = app.getOwner();
    owner.getId();
    owner.getPIN();
    owner.getAddress();
}
最初我认为应该使用某种实体超类,让Person和Trust扩展该类,但它们存储和检索ID和PIN的方式不同。相同行为的不同实现使我找到了接口


我仍然可以使用实体超类,但我觉得我无法准确地表示该实体类的“通用”ID或PIN。我必须实现Person的ID和PIN逻辑或Trust的ID和PIN逻辑,然后在另一个类中重写它。我觉得这不对。我认为实体可以是Person和Trust扩展的抽象类,但我不确定这是否比使用接口更好。

您回答了自己的问题

我走的是正确的路还是应该走的路 你的做法是否有所不同?事情 这让我停顿了一下,这是事实 并不是每个人都是主人 或者是付款人

我越想越觉得 所有者和付款人不是“行为”,所以 就像“分类”一样,是吗 在这里使用接口 不对

接口用于定义行为


您尝试过子类方法吗?

以这种方式使用接口可能合适,也可能不合适。如果你在猜测自己,那么你可能太早介绍了他们

接口的实际用途是允许一段代码针对多个实现运行,例如

interface Contactable
  Address getAddress()
end

class Person implements Contactable
  Address getAddress(){
    ...
  }
end

class Company implements Contactable
  Address getAddress() {
    ...
  }
end

class RenewalReminderJob extends CronJob {
  public void perform() {
    for(Contactable upForRenewal : listOfCompaniesAndPeople) {
      remind(upForRenewal)
    }
  }
}
通常,最好从具体的类开始,然后在发现要对包含相同信息的不同类执行操作时引入接口(使用重构)。在上面的示例中,它将是地址

随着代码库的开发,主动搜索接口的过程可能会非常强大,它允许您发现可能不太明显的概念。

“所有者和付款人与其说是行为,不如说是分类。”

是否有与之相关的行为?例如,您可能需要一个方法

sendInvoice(Payor payor)


如果是这样,那么您可能需要这些接口,特别是当它们可能是个人或公司时。

您可以做的一件事是从继承切换到包含。与其说“个人或信托可以是所有者或付款人”,不如说“个人和信托可以包含所有者或付款人”:


不过,我不确定这是否是正确的答案,因为我不确定“所有者”和“付款人”分类背后的业务逻辑。如果一个人是所有者,这是否意味着他可以拥有任何应用程序?或者,这仅仅意味着这个特定的人拥有这个特定的应用程序吗?如果后者为真,那么您可以从公共基础接口(f.ex.“LegalEntity”)扩展Person和Trust,并使用而不是instanceof检查来提供特定于子类的行为

您的界面没有问题。
Owner
界面仅仅意味着能够拥有东西,而且,除非你想对穷人
Timmy
极不公平,否则我看不出有什么理由阻止他拥有东西


关于你的关切,我认为您有点过分保护:在您的系统中的任何时候都会有多个
所有者
实例,我看不到任何潜在的开发人员假设他们可以选择任何一个并将其视为特定应用程序的所有者。

实现这一点的正确方法是这样的 应用程序具有“角色”实体(即实体在应用程序上扮演不同的角色)

实体可以是个人/组织/受托人等

因此,如果你以这种方式构建你的类,你就不会有问题

作为一个例子,我可以用

             entity1 (insured )       - person 
             entity2 (payer )         - person 
             entity3 (beneficiary)    - trustee
             entity4 (broker)         - organisation

你什么时候会使用所有者的蒂米实例,你会做什么样的“所有者工作”?在我看来,实体是所有者还是付款人只是在特定应用程序的上下文中定义的,在那里你已经知道哪个是谁。类型系统在定义你所说的语义方面可能有点弱。传递这种默认信息通常是通过其他方式完成的,选择结对编程、综合测试/规范套件,包括如何使用每个类或老式powerpo的示例
public class Person {
    public Owner getOwner() { /* will return null if this person is not an Owner */ }
    public Payor getPayor() { /* will return null if this person is not an Payor */ }
}

public class Trust {
    public Owner getOwner() { /* will return null if this trust is not an Owner */ }
    public Payor getPayor() { /* will return null if this trust is not an Payor */ }
}
             entity1 (insured )       - person 
             entity2 (payer )         - person 
             entity3 (beneficiary)    - trustee
             entity4 (broker)         - organisation