2

我在我的一个程序中使用装饰器模式来装饰具有不同毕业要求的课程。几个例子:

new BasicCourse("Course Foo", 1);  // parameters are name and credits

new DisciplinaryBreadth(DBR.MATH, new BasicCourse("Course Foo", 1));

new IntroToHumanities(IHUM.FIRST_QUARTER,
        new ProgramInWritingAndRhetoric(PWR.FIRST_YEAR,
        new BasicCourse("Course Bar", 2)));

new ProgramInWritingAndRhetoric(PWR.FIRST_YEAR,
        new IntroToHumanities(IHUM.FIRST_QUARTER,
        new BasicCourse("Course Bar", 2)));

后两者在交换性质上是相同的。

我正在实现hashcode()and equals(),以便可以在 HashMap 中使用 Courses。我必须更改 Eclipse 的自动生成的 equals 函数,以便可交换的课程彼此相等。我不了解哈希码的生成以及我的平等,所以我想知道我是否需要对哈希码函数做同样的事情。

以下是 Eclipse 为每个装饰器提供的内容:

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((inner == null) ? 0 : inner.hashCode());
        result = prime * result
                + ((requirement == null) ? 0 : requirement.hashCode());
        return result;
    }

这会为交换课程产生相同的哈希吗?

编辑
每个装饰器都有一个requirement变量,该变量对应于具有该装饰器的课程所满足的要求。例如,DisciplinaryBreadth 类具有 DBR 类的要求,它是可能的 Disciplinary Breadth 要求的枚举。ProgramInWritingAndRhetoric 类具有 PWR 类的要求,这是可能的 Program in Writing 和 Rhetoric 要求的枚举。等等。

每个装饰器中的需求变量是一个不同的枚举。所有课程都实现了获得各种毕业要求的方法(例如getDbrs()getIhum())。

装饰器调用他们内部课程的方法来处理除了他们定义的需求之外的所有需求。例如 IntroToHumanities 类调用inner.getDbrs()and inner.getPwr(),但使用它的需求变量作为它的getIhum()方法。getName()他们还为and方法调用其内部 Course 的getCredits()方法,而 BasicCourse 类使用其构造函数中设置的最终成员定义这些方法。

inner变量只是每个装饰器包装的内部课程。内部变量和需求变量在每个装饰器的构造函数中设置并且是最终变量。

这是 ProgramInWritingAndRhetoric 类的 equals 方法:

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!(obj instanceof Course))
        return false;
    Course other = (Course) obj;
    if (getName() == null) {
        if (other.getName() != null)
            return false;
    } else if (!getName().equals(other.getName()))
        return false;
    if (getCredits() != other.getCredits())
        return false;
    if (!getDbrs().equals(other.getDbrs()))
        return false;
    if (!requirement.equals(other.getPwr()))
        return false;
    if (!getIhum().equals(other.getIhum()))
        return false;
    if (!getEc().equals(other.getEc()))  //another Graduation Requirement
        return false;
    return true;
}

我跳过了一些对 null 的检查,因为我在构造函数中检查了它们,所以你不能使用 null IHUM 创建课程,例如。其他毕业要求的实现也类似,唯一的区别是使用要求变量的位置。

4

2 回答 2

2

@Eva我不同意你应该让你的IDE生成你的哈希码方法的建议,但也许我是过时的。

基本上,在生成散列时,您的目标是(尽可能合理地)基于对象的成员变量获得分布良好且唯一的散列集。

因此,您应该获取成员变量的值(原始值)或哈希码(复杂对象时),并使用它们以分布良好的方式计算哈希码(因此通常使用素数作为乘数) 并且不太可能引起碰撞。

因此,合理的 hashCode() 将使用与您的 equals 方法相同的成员变量,但采用值/哈希值并将它们与素数相乘。

请记住,唯一的、良好分布的散列的唯一保证是提前知道可能的全部对象,在这种情况下,您实际上可以预先分配散列,但这很少是有效的解决方案。

这是对您要实现的目标的一个很好的解释-http: //eclipsesource.com/blogs/2012/09/04/the-3-things-you-should-know-about-hashcode/

于 2013-01-23T17:33:45.600 回答
1

根据 codeghost 的回答,我认为这可能是正确的哈希码(在 IntroToHumanities 类中):

public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + getCredits();
    result = prime * result + 
            ((getName() == null) ? 0 : getName().hashCode());
    result = prime * result + getDbrs().hashCode();
    result = prime * result + getPwr().hashCode();
    result = prime * result + requirement.hashCode();
    result = prime * result + getEc().hashCode();
    return result;
}
于 2013-01-23T17:51:26.707 回答