【问题标题】:OOP - best approach for adding property to classOOP - 将属性添加到类的最佳方法
【发布时间】:2016-11-20 21:51:15
【问题描述】:

我们开发了一个用 Java 编写并使用 Hibernate 映射的 HR 应用程序;其中一个特点是招聘阶段。

Candidate 类的建模如下:

public class Candidate  {
    private String id;
    private Integer candidateCode;
    private GregorianCalendar birthDate;
    private String italianFiscalCode; //unique code for italian people 
}

由于到目前为止我们只为市场开发代码非常依赖于特定法规,请查看 fiscalCode 类属性。

要求我们将这个概念推广到其他市场,例如唯一标识符可以不同,可以由多个字符串组成或根本不存在。

我想到的第一件事:

1 - 只需将该字段重命名为 countryIdentifier 并在需要时为特定国家添加其他字段。

private String countryIdentifier; //general unique code
private Integer greekAddedCode;   

这意味着在需要的地方重构代码(所有使用旧 italianFiscalCode 的地方),重命名 DBMS 列(并最终添加其他列)并修改使用该字段的所有查询。

这在我看来是一个糟糕的实现

2 - 子类 Candidate 创建 ItalianCandidateGreekCandidate 并在子类中移动特定字段。

问题是Candidate 类已经被HeavyCandidate 子类化了,它具有优化Hibernate 映射的唯一功能,因为我们将所有“重”属性(多对一和集合)移动到重类(这是我们所有 bean 都遵循的方法)。

在这种情况下,最正确的方法是什么?

【问题讨论】:

  • "问题是Candidate 类已经被HeavyCandidate 子类化了"。不,Candidate 应该有一个 HeavyCandidate 类型的字段 - 这不是 is a 关系。您当前的做法是对继承的严重滥用,也是为什么不应以这种方式滥用继承的一个很好的例子。
  • 感谢您的回复@BoristheSpider。我想这种方法是为了能够通过 Hibernate 轻松映射 bean,但我同意它不是正确的。

标签: java hibernate oop inheritance design-patterns


【解决方案1】:

我将创建一个接口Identifier(不确定名称),该接口由GreekIdentifierItalianIdentifier 等类实现。然后我会在Candidate 中添加一个字段:

Identifier identifier;

GreekIdentifier 的实现将如下所示:

public class GreekIdentifier implements Identifier {
    String countryIdentifier;
    int addedCode;

    //constructor, getters, setters ...
    //actual behaviour, Indentifier @Overrides ...
}

如果countryIdentifier 确实是所有标识符都具有的东西,您甚至可以将其移至(抽象)基类。

【讨论】:

  • 标识符(任何方法)包含什么?还是只是标记界面?
  • 它将包含所有标识符共有的任何行为。最终结果是什么?你想用这些信息做什么?什么标识符?我对国家标识符和代码一无所知...
  • 感谢托德,我认为这是一种更正确的方法,可以避免 Cadidate 子类化的问题。关键是那时我应该创建一个单独的表来存储标识符,并且我确信为检索数据添加的连接将是一个缺点。
【解决方案2】:

我认为一个好方法是创建一个抽象类。通过使用它,它将为每个候选对象提供一个通用框架,并暗示特定方法需要在扩展类中。这也适用于构造函数,是制作通用大纲的好方法

public abstract class Candidate{
    //Use Vars Here
    private String name;

    //Constructor for the abstract class
    public Candidate(String n){
        //Add Normal Constructor Code Here
        name = n;
    }

    //A possible abstract method that may vary based on the type of candidate
    public abstract String getType();   //Abstract Methods must be defined in a child class
}


public class SpecificCandidate extends Candidate{
    //Add other needed vars
    //Normal Constructor
    public SpecificCandidate(String n){
        super(n);        //This gets passed into the abstract constructor
    }

    //Define the Abstract Method
    @Override
    public String getName(){
        return "Specific";
    }
}

【讨论】:

    【解决方案3】:

    在我看来,最好的办法是扩展类并创建子类。

    然后您可以做的是向该类添加必填字段。

    所以

    public class YourCandidate extends Candidate{
    
       // extra fields
    }
    

    为候选人和其他希腊候选人之间的关系映射创建一个单独的表。

    通过采用这个:

    1. 您可以防止重复代码。
    2. 您将坚持 OOP 的主要原则并保持层次结构。这可能是一个很好的example
    3. 这样您就不必修改当前的类和表。,这总是一件好事。

    【讨论】:

    • 感谢您的回答。我将阅读链接的文章,对于该类已经被子类化的事实,您有什么建议吗?
    • @frankieta 我猜你可以为所有需要该子类的国家/地区扩展该子类。
    • 你的意思是扩展HeavyCandidate吗?与 Identifier 字段相比,该类加载了太多不是主要信息的数据。
    猜你喜欢
    • 2015-03-16
    • 1970-01-01
    • 2015-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-16
    • 2023-03-13
    • 2020-08-03
    相关资源
    最近更新 更多