【问题标题】:Decide which Enum return based on object properties根据对象属性决定返回哪个 Enum
【发布时间】:2018-01-28 23:21:38
【问题描述】:

我想知道是否有一些设计模式可以帮助我解决这个问题。

假设我有一个类Person,它具有三个属性:namenicknamespeaksEnglish,以及一个带有TypeOneTypeTwoTypeThree 的枚举PersonType

假设PersonnicknamespeaksEnglish,它就是TypeOne。如果它有nickame 但没有speaksEnglish,则它是TypeTwo。如果没有nickame,则为TypeThree

我的第一个想法是有一个带有一些if-else 并返回相关Enum 的方法。以后我可以在Person和其他类型的PersonType中有更多的属性来决定。

所以,我的第一个想法是用一堆if (...) { return <PersonType> }switch-case 创建一个方法,但我想知道是否有一些设计模式可以用来代替ifsswitch-case

【问题讨论】:

  • 向 Enum 添加一个抽象方法怎么样,比如说方法 'boolean test(Person)',这样每个 Enum 类型都能够检查人员是否属于该类型。稍后您只需要遍历 Enum.values() 并调用 test(person)。不确定是否是最好的主意,但您会将逻辑保留在一个地方,避免所有那些 if/else
  • 你的Person对象是可变的还是不可变的?

标签: java oop design-patterns enums


【解决方案1】:

我会建议你对不可变对象使用简单的继承。

所以,首先你必须创建抽象类:

public abstract class AbstractPerson {

    private final String name;
    private final Optional<String> nickname; 
    private final boolean speaksEnglish;
    private final PersonType personType;

    protected AbstractPerson(final String name, final Optional<String> nickname, final boolean speaksEnglish, final PersonType personType) {
        this.name = name;
        this.nickname = nickname;
        this.speaksEnglish = speaksEnglish;
        this.personType = personType;
    }

    public String getName() {
        return name;
    }

    public Optional<String> getNickname() {
        return nickname;
    }

    public boolean getSpeaksEnglish() {
        return speaksEnglish;
    }

    public PersonType getPersonType() {
        return personType;
    }

}

使用PersonType 枚举:

public enum PersonType {

    TypeOne, TypeTwo, TypeThree;

}

现在,我们在子类中有对应构造函数的三个选项:

public final class EnglishSpeakingPerson extends AbstractPerson {

    public EnglishSpeakingPerson(final String name, final String nickname) {
        super(name, Optional.of(nickname), true, PersonType.TypeOne);
    }

}

public final class Person extends AbstractPerson {

    public Person(final String name, final String nickname) {
        super(name, Optional.of(nickname), false, PersonType.TypeTwo);
    }

    public Person(final String name) {
        super(name, Optional.empty(), false, PersonType.TypeThree);
    }

}

在这种情况下,我们的具体类是不可变的,并且它的类型是在创建时定义的。您不需要创建 if-else 阶梯 - 如果您想创建新类型,只需创建新的类/构造函数。

【讨论】:

    【解决方案2】:

    我不认为Type 真的可以成为Person 的属性。我不反对@ByeBye 的回答,但是通过这种实现,当引入新类型时,您最终仍会更改Person 类。

    X类型的人最终就是人本身。假设ManagerDeveloper 都是公司的员工,因此将它们作为派生自Employee 的专用类很有意义。同样,在您的情况下,将人员类型作为属性然后执行所有 if-else 操作显然违反了 SOLID。

    我会改为使用 Person 类的特定实现并将其自身标记为抽象类。

    public abstract class Person {
        public Person(string name) {
            Name = name;
        }
        public abstract string Name { get; set; }
        public abstract string NickName { get; set; }
        public abstract bool SpeaksEnglish { get; set; }
    }
    
    public class TypeOnePerson : Person {
        public TypeOnePerson(string name, string nickName) : base(name) {
            NickName = nickName; // Validate empty/ null 
        }
        SpeaksEnglish = true;
    }
    
    public class TypeTwoPerson : Person {
        public TypeOnePerson(string name, string nickName) : base(name) {
            NickName = nickName; // Validate empty/ null 
        }
        SpeaksEnglish = false;
    }
    

    我也认为这个问题与语言无关,它是一个纯粹的设计问题。所以请多多包涵,因为上面的代码是用 C# 编写的。不过这没关系。

    【讨论】:

    • 我喜欢你的选择,但我认为该类型必须是类的一部分——我们必须避免使用像 instanceOf 这样的结构。如果我们想要按类型或类似的过滤器会很有帮助
    • 您不需要为类型检查执行instanceOf。因为您的所有代码都将与 Person 抽象而不是特定实现进行对话。特定的实现只会在代码需要Person 的地方注入。
    • 但是如果你有Person的列​​表并且你只想过滤TypeTwoPerson你没有这样的信息
    【解决方案3】:

    就 OO 原则而言,为什么要创建具有可选属性组合的对象?如果它的问题是一两个,那么 Optional 方法将保持可维护性,但类型将基于许多组合(将来的代码将充满布尔代数)并且问题也说“.. .将来我可以在Person和其他类型的PersonType中有更多的属性来决定。“。

    我建议使用装饰器模式的方法,它允许我们创建具有完全代码重用的自定义对象。 Person 将是 Component 和 Optional 属性(它们是类型,例如带有验证作为行为的 NickName)将是具体的装饰器。

    任何对 Person 的添加添加新的 Concrete Decorator 类型仍然是两个独立的问题。 Decorator Pattern 是此类需求的最佳候选者。它的意图来自 GOF 书籍(由 Erich gamma 撰写)模式目录说 - “动态地将附加职责附加到对象。装饰器为扩展功能提供了一种灵活的替代子类化方法”。 [尽管对于极少数预期的扩展,早期的答案更有意义。]

    【讨论】:

      猜你喜欢
      • 2021-09-10
      • 2015-03-06
      • 1970-01-01
      • 2019-04-02
      • 1970-01-01
      • 1970-01-01
      • 2021-07-09
      • 1970-01-01
      • 2014-03-15
      相关资源
      最近更新 更多