为我的 类 中使用的通用 pojo 建模

model a generic pojo to use in my classes

我正在尝试创建一个像通用 POJO 一样工作的对象,因为我必须通过不同的对象传递它,并且我需要一个接口,它们可以通过该接口访问它的属性。

目前我使用一个具有 getField 方法的基础对象来完成它,我在其中输入参数的名称并通过反射获取它,它是这样的:

public abstract class BasePOJO{

    public Object getField(String fieldName){

        try {
            return this.getClass().getField(fieldName).get(this);

        } catch (NoSuchFieldException ex) {
            Logger.getLogger(BaseRequest.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SecurityException ex) {
            Logger.getLogger(BaseRequest.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(BaseRequest.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(BaseRequest.class.getName()).log(Level.SEVERE, null, ex);
        }

        return null;
    }
}

我使用它来扩展 class,如下所示:

public class CredentialsPOJO extends BasePOJO{
    public String username;
    public String password;
}

并像这样调用属性:

credentialsPojo.getField("username");

我很快就创建了这个,它很糟糕但是很有效。但我想将其更改为更像样的东西来为该对象建模。

他创造了 el siguiente:

public class BasePOJO{

    private Map<String, Object> parameters = new HashMap<>();


    public void addParameter(String paramName, Object value){
        parameters.put(paramName, value);
    }

    public Object getParameter(String paramName){
        return parameters.get(paramName);
    }
}

我更喜欢这个对象,它更面向对象的解决方案,问题是它只有 returns 一种对象类型

想法是使用此 POJO 的对象可以以通用方式访问它们的属性。 如果有设计模式可以更好的解决这个问题,那么我可以实现它。

您即将创建 inner platform。这通常是个坏消息。

使用通用 POJO,您将无法在调用方法时从 IDE 获得支持(因为它们根本不存在)。此外,如果您忘记某个字段或拼写错误,您将 运行 陷入困境。如果不冒字符串中的名称出现问题的风险,重构也是不可能的。

如果您的项目中并不孤单,您的同事是否能够理解并使用此解决方案? 6个月、1年、5年后你能回来吗?

尽可能简单地使用 属性 方法(getXyz、setXyz),并根据用途在具有不同 类 的对象上调用它们。

查看你的IDE,它很可能能够为你的字段自动生成getter和setter方法,所以本质上,你只需要设置字段然后按下一个按钮来完成剩下的工作。 (IntelliJ IDEA 和 Eclipse 做到了这一点,我还提到了我所知道的两个。我很确定 Netbeans 也是如此。)

如果您不确定 类 需要什么,请创建 Use Cases 来解决您的问题。一个好的开始是为用例文本中的名词创建 类 并为动词创建方法。之后,您可以开始概括。 (尽管提防 API、框架和万能的解决方案,即使它们很诱人……我也爱他们!直到我意识到我正在构建一个静态站点生成器而不是打印一些 HTML-文件...通常是几周后...)

说了这么多,可能有一些框架可以从数据库模式(Hibernate?)、Web 服务等生成 类,也许这就是可行的方法。无论如何,那些仍然 类 具有实际的 属性 方法等

希望对您有所帮助!

类似的东西在 PHP 中有效(例如 Magento - 魔法方法),老实说,我认为这是一个糟糕的机制。

为什么?

如果字段不存在,您无法 IDE 控制。你的 class API 不清楚所以出错的风险很高。您必须研究实施才能知道可以使用哪些字段。在您的示例中,您还通过创建字段 public 来打破封装,因此任何人都可以直接使用它,而无需您的方法。

这些天自动生成 getters/setters 没有必要这样做。如果你想摆脱样板 getter/setter 代码,你可以使用 Lombok 例如。

术语说明

POJO = Plain Old Java对象,即没有使用一些第三方注解,这些注解用于"decorate"对象行为( Hibernate的实体注解,或者已经提到的生成方法的Lombok)。符合您的情况的是 Bean = class 每个 class 字段都有 getter 和 setter。

解决你的问题

// derive type from left side of the assignement operator
public <T> T getProperty(String paramName){
    return (T) parameters.get(paramName);
}

这样,您可以输入如下内容:

String name = pojo.getProperty("name");
Integer age = pojo.getProperty("age");

缺点

由于给定的方法只是显式地将映射值转换为"any type on the left side of the assignment operator",因此无法实现编译时检查,这将在您编写后立即给您警告:Integer age = getProperty("name");。请注意,在执行代码时,还有运行时类型检查。这样的分配将抛出 ClassCastException

请记住,只要您将映射定义为 Map<String,Object>,就无法进行编译时检查 - 给定键下的值几乎可以是任何值。这也适用于反射方法,因为 getField(String) returns 属性值隐藏在 Object 类型中。

要进行编译时检查,请阅读建议部分。

推荐

我强烈建议您使用项目 Lombok,正如@Peteef 已经提到的那样。请确保您还在 IDE 中安装了 lombok 插件,否则自动生成的方法会产生语法错误。

注释@Data will generate getter for each field and setter for each non-final field. In addition @Data annotation will generate also equals and hashCode methods which are important when objects are stored in Set or Map个集合。如果您想检查两个对象是否相同(相同的字段值),方法 equals 可能也是可取的。

@Data
public class Credentials {
    public String username;
    public String password;
}

请注意,如果这些 classes 应该用作简单的数据持有者,您仍然可以使用没有 getters/setters 的 classes 和 public 字段。当然,这不是 OOP,但您不必盲目地遵循每个约定(有时它们会适得其反)。

public class Credentials {
    public String username;
    public String password;
}