枚举设计决定的常规具体方法 [英] Constant specific methods for enum design decision

查看:110
本文介绍了枚举设计决定的常规具体方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更多的设计问题就是这个。首先,我有一个枚举:

 枚举WageType {
MONTHLY {
public int getWageRatePerUnit(){
return 60000;
}

public boolean isPaymentTime(DateTime date){
return date.getDayOfMonth()== 29;
}
},
DAILY {
public int getWageRatePerUnit(){
return 2500;
}

public boolean isPaymentTime(DateTime date){
return date.getHourOfDay()== 20;
}
};

public abstract int getWageRatePerUnit();
public abstract boolean isPaymentTime(DateTime date);
}

现在我有2个抽象方法,在枚举常量中各自的实现。真正的场景包含了一些冗长的业务逻辑,最后我用3或4个这样的方法。



但是我有一种感觉,我搞砸了我的枚举。这被认为是不好的设计实践,将业务逻辑特定于不同的枚举类型在不断的具体方法?如果我宁愿实现一个接口,并在那里定义方法,并让所有的枚举常量实现它们会有什么不同?当然,在这之后我必须使用接口引用,但是我必须看看它是否适用于hibernate映射。目前,我使用 @Enumerated(EnumType.String)将枚举常量存储为实体的一部分。所以,我期望另一种方法不会影响这部分,即End行为应该保持不变。



BTW,我不认为一个接口将被要求,因为我不会有一组单独的具有类似行为的枚举常量。其他选项可能是某种实用类,用于处理这些枚举常量。并且只是传递方法它所处理的枚举类型。



你说什么?我应该采取哪种方法?关于使你的枚举实现一个接口vs扩展模板方法,我可以开放给任何其他更好的选择吗?

解决方案

对于每个枚举值,我会坚持使用模板方法,因为正如你所说,不会有任何其他枚举或类实现这些方法。 (实现一个界面是有道理的,如果你有很多枚举或类需要履行合同,但这似乎不是这样)。



我个人将枚举作为具有一些约束的类(即它们是最终的和无状态的),但有人认为使用枚举这种方式是 hacky 。我根本不同意,因为我认为使用语言提供的功能是绝对有效的,而模板方法是这样的功能之一。然而,很高兴知道这种方法在一些保守的环境中产生了阻力。



尽管如此,我认为使用枚举中的模板方法使您的代码相当详细即可。我只会采用这种方法,如果模板方法的数量和枚举值的数量很少,如果它被授予,他们将来不会改变。



另一方面,您可以通过使用此代码而不是您的代码实现完全相同的功能:

  public enum WageType {
MONTHLY(60000,29),DAILY(2500,20);

private final int wageRatePerUnit;
private final int hourOfDay;

public WageType(int wageRatePerUnit,int hourOfDay){
this.wageRatePerUnit = wageRatePerUnit;
this.hourOfDay = hourOfDay;
}

public int getWageRatePerUnit(){
return this.wageRatePerUnit;
}

public boolean isPaymentTime(DateTime date){
return date.getHourOfDay()== this.hourOfDay;
}
}

这段代码比你的简单得多,相同的功能。但是,您将无法从数据库检索您的枚举,因为Hibernate不会为其找到默认构造函数。



现在,我相信使用可用的语言功能来解决方案是可以的,但使用它们,因为否则Hibernate将不知道如何实现你的枚举...好吧,这就是我所说的解决方法。



也许你可以使 WageType 实体,让Hibernate像往常一样处理它,并将其与其他实体相关联,并且在实体的方法中或在实体之外的服务类中或在某些实用程序类中实现您的逻辑,无论您喜欢什么。请注意,根据 WageType 实体参与的每个协会的提取策略,这将导致额外的加入或选择(或可能是子选择ugh)。


More of a design question this is. So to begin with, I've an enum:

enum WageType {
    MONTHLY {
        public int getWageRatePerUnit() {
            return 60000;
        }

        public boolean isPaymentTime(DateTime date) {
            return date.getDayOfMonth() == 29;
        }
    },
    DAILY {
        public int getWageRatePerUnit() {
            return 2500;
        }

        public boolean isPaymentTime(DateTime date) {
            return date.getHourOfDay() == 20;
        }
    };

    public abstract int getWageRatePerUnit();
    public abstract boolean isPaymentTime(DateTime date);
}

Now I've 2 abstract methods there, and respective implementation in the enum constants. The real scenario contains some sort of lengthy business logic there and I ended up with 3 or 4 such methods.

But I've a feeling that I'm messing up my enum. Is this considered to be bad design practice, to put business logic specific to different enum types in constant specific methods? What difference would it make if I rather implement an interface, and define methods there, and let all the enum constant implement them? Of course, I would have to use interface reference everywhere after that, but I've to see whether it works well with hibernate mapping or not. Currently I'm storing the enum constants as a part of entities using @Enumerated(EnumType.String). So, I would expect the other approach not to affect this part by much, i.e. End behaviour should remain same.

BTW, I don't think an interface would be require, as I'm not going to have a separate set of enum constants possessing similar behaviour. Other option might be some kind of utility class, to deal with these enum constants. And just pass the methods the type of enum it is dealing with.

What do you say? Which approach should I follow? I am open to any other better option if you can think of?

解决方案

Regarding making your enum implement an interface vs extending template methods for every enum value, I'd stick to the template methods, since, as you said, there won't be any other enum or class implementing those methods. (Implementing an interface would make sense if you had many enums or classes that need to fulfill a contract, but this doesn't seem to be the case).

I personally consider enums as classes with some constraints (i.e. they're final and stateless), but there are people out there arguing that using enums this way is hacky. I don't agree at all, because I think that using the features provided by the language is absolutely valid, and template methods are one of such features. However, it's good to know that this approach generates resistance in some conservative environments.

Despite this, I do think that using template methods in enums makes your code quite verbose. I'd only take this approach if both the number of template methods and the number of enum values is low and if it's granted they won't change in the future.

On the other hand, you could achieve exactly the same functionality by using this code instead of yours:

public enum WageType {
    MONTHLY(60000, 29), DAILY(2500, 20);

    private final int wageRatePerUnit;
    private final int hourOfDay;

    public WageType(int wageRatePerUnit, int hourOfDay) {
        this.wageRatePerUnit = wageRatePerUnit;
        this.hourOfDay = hourOfDay;
    }

    public int getWageRatePerUnit() {
        return this.wageRatePerUnit;
    }

    public boolean isPaymentTime(DateTime date) {
        return date.getHourOfDay() == this.hourOfDay;
    }
}

This code is much simpler than yours and provides exactly the same functionality. However, you wouldn't be able to retrieve your enum from the database, since Hibernate wouldn't find a default constructor for it.

Now, I believe that using available language features to come to a solution is OK, but using them because otherwise Hibernate wouldn't know how to materialize your enum... well, that's what I call a workaround.

Maybe you could make WageType an entity and let Hibernate handle it as usual, and associate it to other entities, and either implement your logic in methods of this entity or in a service class outside of the entity or in some utility class, whatever you prefer. Please be aware that this would lead to an extra join or select (or maybe a subselect, ugh), depending on every association's fetch strategy where the WageType entity participates.

这篇关于枚举设计决定的常规具体方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆