Java方法从通用返回类型返回具体类型

时间:2019-03-27 18:20:22

标签: java oop

我正在尝试创建一个枚举列表,并在枚举中定义了一个抽象方法,每个枚举值都会实现该方法。我面临的问题是抽象类具有通用的返回类型,但是我希望每个枚举值都返回一个具体的类型。 我举一个例子:

public enum Attributes {
    name {
        @Override
        public void createAttribute(Person person) {
            //Do some validations
            //Save in some storage
        }
        @Override
        public Name getAttribute(Person person) {
            // Validations
            // Retreive from storage
            return new Name("test");
        }
    },
    address {
        @Override
        public void createAttribute(Person person) {
            //Do some validations
            //Save in some storage
        }
        @Override
        public Address getAttribute(Person person) {
            // Validations
            // Retreive from storage
            return new Name("test");
        }
    }

    public abstract Object getAttribute(Person person);
    public abstract void createAttribute(Person person);
}

这里的问题是,我需要进行类型转换以获取不推荐的具体对象,并且我也没有任何类型的安全性。我应该如何做,以便使用枚举值可以得到我的具体对象而不是通用对象。

现在我想称其为

Arrays.stream(Attributes.values()).forEach(r -> {
    r.createAttribute(person);
}
final Address address = Attributes.address.getAttribute(person);
final Name name = Attributes.name.getAttribute(person);

因此,现在每当我需要添加新属性时,我都不想每次都在Person类中为其编写create方法。我只是将其添加到枚举,它就被创建了。但是现在,由于我在枚举中有create方法,因此我也希望getAttribute在此处出现。

1 个答案:

答案 0 :(得分:0)

  

这里的问题是,我需要进行类型转换以获取不建议使用的具体对象,并且我没有任何类型的安全性。

您是对的。给定一个具有关联的枚举常量E的枚举类型C,表达式E.C的类型为E。 Java没有提供用于命名或表示该表达式的较窄类型的机制。含义之一是,尽管枚举实例可以实现具有协变返回类型的方法,但协变在实例外部不可见。如果出于某种目的而依赖于这些实例方法之一的较窄的返回类型,则强制转换是唯一的选择。

您是对的,此类强制类型转换类型不正确。它们不能由编译器检查,实际上,作为程序员,您可能会弄错它们。但是执行编译时检查的信息不是由该语言表示的,因此,今天定义的该语言没有变通办法的范围。

  

我应该怎么做,以便使用枚举值可以得到具体对象而不是通用对象。

应该选择一种完全不同的方法,而不涉及枚举。

如果坚持使用枚举,则必须采用依赖于枚举实例的方法来执行依赖于其自身特定特征的任何任务。因为您一直这么问,所以一种可能性是对双调度实施变体。而不是getObject()方法,您会得到类似

void acceptReceiver(AttributeReceiver r, Person p);

配对
public interface AttributeReceiver {
    default void receiveName(Name name) { /* empty */ }
    default void receiveAddress(Address addr) { /* empty */ }
}

当然,枚举实例必须适当地实现acceptReceiver

您可能想直接使用它来获取属性,但是可以使用它来获取属性,如下所示:

class Example {
    Name name;
    Address address;

    void retrieveAttributes(Person person) {    
        AttributeReceiver receiver = new AttributeReceiver() {
            public void receiveName(Name n) { name = n; }
            public void receiveAddress(Address a) { addr = a; }
        };
        Attributes.name.acceptReceiver(receiver, person);
        Attributes.address.acceptReceiver(receiver, person);
    }
}

但是当您可以选择使用{em>方法(无论是在Person还是什至在[em]上时,这就是 令人敬畏的 回旋处一些非枚举实用程序类。我仍然认为在此处使用枚举不会带来任何好处。我认为使用枚举会比没有枚举更复杂,更难以理解和维护。

根本问题是您要抽象出您真正关心的细节。这是一个深层的设计缺陷。您可以对它进行编程,但是最好首先选择一个更合适的抽象级别。