【问题标题】:How should I populate my object?我应该如何填充我的对象?
【发布时间】:2015-12-13 16:10:40
【问题描述】:

我有一个想要填充信息的对象。我从许多不同的服务中检索信息。我创建了一个辅助类,它有一个公共方法,然后有许多私有方法来完成调用服务的工作。我写的效果很好,但我不确定这是否是正确的方法。

您可能想知道为什么我需要一个包含所有这些信息的对象。我需要将它全部放在一个对象中,因为我从这个 java 对象创建了一个 json 对象并将其传递给 javascript 层。

我的方法有什么问题,是否有我应该遵循的编程范例来做这样的事情?

例子:

Person 对象,包含名字、姓氏、年龄、身高、体重、喜爱食物列表、喜爱国家列表、cmets 列表的 getter 和 setter。

  • 服务 1 提供名字、姓氏、年龄、身高和体重
  • 服务 2 给出最喜欢的国家列表和最喜欢的食物列表
  • 服务 3 给出了该人制作的 cmets 的列表

我有一个如下所示的 personH​​elper 类:

public class PersonHelper{

public Person getPerson(userDetails){
    Person person = new Person();
    this.setPersonDetails(person, userDetails);
    this.setFavourites(person, userDetails);
    this.setComments(person, userDetails);

    return person;
}

private Person setPersonalDetails(Person person, UserDetails userDetails){

    returnedObj = callToService1(userDetails);
    person.setFirstName(returnedObj.getFirstName());
    person.setLastName(returnedObj.getLastName());
    person.setAge(returnedObj.getAge());
    person.setHeight(returnedObj.getHeight();
    person.setWeight(returnedObj.getWeight());

    return person;
}

private Person setFavourites(Person person, UserDetails userDetails){

    <List>favsList = callToService2(userDetails);
    person.setFavourites(returnedObj.getFavs(favsList));

    return person;
}

private Person setComments(Person person, UserDetails userDetails){

    <List>commentsList = callToService3(userDetails);
    person.setComments(returnedObj.getComments(commentsList));

    return person;
}

}

然后在我的控制器中调用

person = personHelper.getPerson(userDetails);
jsonResponse = jsonProcessor.writeAsString(person);

return jsonResponse; // returns the ajax response to js

提前感谢您的任何帮助或建议。

编辑:经过更多研究,我发现我正在填充的对象被称为数据传输对象,我正在使用 Java Bean 方法填充它。

【问题讨论】:

  • 看起来不错,我会这样做
  • 我觉得不错。我只是在这里陈述我的观点 - 你可以在 getPerson 方法本身中获得这 3 种方法的陈述。由于这些是简短的方法,它们无论如何都会在运行时内联。另一个变化是您不必明确地说this.setPersonDetails(),只需setPersonDetails() 就可以了,因为this 隐含在其中。
  • 谢谢(你们俩)。我只是觉得有些不对劲。有些方法比问题中的方法大。此外,我对所有私有方法都有单元测试(我将它们更改为受保护的,以便我可以测试它们)。所以这就是为什么我把它分成私有/受保护的方法。

标签: java oop object paradigms


【解决方案1】:

现在有一种趋势是限制对象的可变性,因此基于 setter 的方法虽然可行,但有时并不被视为创建对象的最佳方式,即使是数据传输类型的对象也是如此。要考虑的另一件事是有多少对象彼此了解以及它们了解多少 - 您的 PersonH​​elper 类似乎需要了解有关 UserDetails 和 Person 的几乎所有内容。因此,如果您将字段添加到 Person,您需要将其添加到 UserDetails 并添加到 PersonH​​elper 以填充该字段。

对于您的对象类型,您可能会发现 Builder 模式很有用。构建器是一种短期瞬态对象,旨在为构建收集数据。构建器通常会有一个流畅的 API,并被传递给传输类的(私有)构造函数。这意味着您负责构建对象的所有代码都清楚这是它的责任,因为它与 Builder 一起工作。同时,构造的传输对象实际上是不可变的,并且更容易推理代码的线程安全性并理解某些东西可能在不同部分具有什么值。

public class Person {
    private final String firstName;
    private final String lastName;

    private Person(final PersonBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
    }
    ... usual getters etc ...

    public static class PersonBuilder {
        private String firstName;
        private String lastName;

        private PersonBuilder() {
        }

        public PersonBuilder withFirstName(final String name) {
            this.firstName = name;
            return this;
        }

        public PersonBuilder withLastName(final String name) {
            this.lastName = name;
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }

    public static PersonBuilder newPerson() {
        return new PersonBuilder();
    }
}

在此示例中,构建器有点过于繁琐,但是当您有二十或三十条不同的数据时,这些数据在某种程度上是可选的,它可能是有意义的,并且构建代码非常易于阅读......

Person.newPerson().withFirstName("Sam").withLastName("Spade").build()

在我看来,您的“UserDetails”对象可以变成一种构建器。因此,您的“PersonH​​elper”类最终只会调用 userDetails.build(),而不是知道 Person 对象(和 userDetails 对象)包含哪些字段。

【讨论】:

  • 感谢您的回答。如果我总是(并且将总是)填充 Person 对象上的所有字段,使用构建器模式是否适用?如果某些字段是可选的,这似乎很有用。另外,(这可能是一个愚蠢的问题)在你的场景中我会在哪里调用我的服务?在构建器方法中还是仍在调用构建器的助手/控制器中?
  • 这个答案给了我很多信息,但我在整个应用程序中都使用 Java Bean,所以会坚持这种模式。所以我将另一个答案标记为正确。不过再次感谢。
【解决方案2】:

您的问题没有通用范式,但这里有一些设计技巧:

  1. 您的个人数据(姓名、收藏夹)似乎分布在多个数据存储中,您必须将它们全部放在您的 PersonH​​elper 类中。我不知道这个服务是否在其他地方使用,但从控制器的角度来看,这个助手也应该是一个服务。

  2. 由于您的服务调用是独立的,您可以并行执行它们

  3. 对于某些类型的应用程序,如果您在 UI 级别公开这些服务会更好。例如,如果数据以不同的 UI 块呈现,客户端可以发出多个异步请求,并在收到响应后立即显示数据。

【讨论】:

  • 1) 是的,没错。数据是分布式的。如果这个助手是一个服务,它就是一个调用其他服务的服务。这是常见的做法吗?
  • 2) 你的意思是使用线程,比如stackoverflow.com/questions/11218720/…
  • @GreenRails 1. 这取决于服务的实现方式。如果它们只是没有 AOP 开销的单例,您可以轻松地从另一个服务调用一个服务。如果服务调用调用了 AOP 钩子,则应该对其进行审查。 2. 是的,您可以使用 ExecutorService(例如),将任务传递给它,然后从 Futures 中收集结果。
  • 3) 这就是应用程序的设计方式。这个“Person”对象只是一个例子。我的实际对象有一些数据和一些规则,所以它们都需要结合在一起。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-08
  • 1970-01-01
  • 1970-01-01
  • 2013-07-10
  • 2020-08-30
  • 1970-01-01
相关资源
最近更新 更多