封装和吸气剂

Encapsulation and Getters

我正在读这个 article 关于为什么 gettersetters 是邪恶的。这篇文章并没有说不要永远使用它们,但是,它告诉你以一种限制使用这些方法的方式思考,或者引用这篇文章:

Don't ask for the information you need to do the work; ask the object that has the information to do the work for you.

当您需要在 GUI 中显示数据但没有 getter 方法时会发生什么?这篇文章简要介绍了这一点,但并不全面。它提到将 JComponent 传递给 class,但如果您更改了 GUI,则可能需要进行大量修复工作。

例如,您有一本书 class(限制此示例以保持其可读性)。

public final class Book {

    private String title;
    //Authors is class with the attributes authorFirstname, authorLastname
    private List<Author> listofAuthors;


    public Book(String title, List<Author> listofAuthors)
    {
        //initialization
    }

    //other methods that do work
}

如果我有一个 GUI,它有一个 JTextField 来显示书名和一个 JTable 来显示作者列表,我该如何将我的方法写到 "do the work"我并显示结果?这是一个需要 getter 的时代吗?

你问的是一种为你显示所有信息的方法吗?我不关注了。

如果这就是您要问的,我的建议是:不要将它写在 class 中,其中包含 window 代码。不会很干净。使用该方法创建一个新的 class(是的,吸气剂是必需的,它们使 OOP 更容易,但这是有偏见的)。

如果我想循环访问一个列表,我会做一个 StringBuilder 和一个 for 循环,它会添加作者的名字。然后,使用方法 return 作者列表。

List<Authors> a;
StringBuilder d = new StringBuilder();
for (int i = 0; i < a.size(); i++) {
    d.append(a.get(i).getName() + ", ");
}
return d.toString();
//It's just sudo code, but still.

这样想:Getter(public 函数)是私有属性的桥梁。

我会给你写一个简单的例子来使用 OOP 修改你的 TextField。

图书class:

public final class Book {
private String title;
//Authors is class with the attributes authorFirstname, authorLastname
private List<Author> listofAuthors;


public Book(String title, List<Author> listofAuthors)
{
    //initialization
}
public String getTitle() {
return this.title; }
}

图形用户界面:

author1 = new Author("jhon");
author 2 = new Author("alsojhon");
list = new ArrayList();
list.add(author1);
list.add(author2)
b = new Book("stack",list);
JTextField field;
field.setText(b.getTitle());

您可以创建三种 classes:

  1. 实体,class表示一种业务概念并且只有一个唯一 ID,如 Client class,Id 为用户名。它通常是一个可变的class。您应该在此处拥有所有业务逻辑。你不应该用getters和setters打开他的数据。

  2. 值对象,class表示业务概念但没有唯一 ID 的元素,例如电子邮件 class。它通常是 imm.utable class。您应该在此处拥有所有业务逻辑。

  3. 数据结构(DTO 的一种),classes 只保存数据,没有行为,也许你有 setter 和 getter 来访问这些数据。

如果我没有访问器,需要访问所有客户端数据怎么办?那么,您应该将 Client 转换为 DTO。您可以使用像 Orika 这样的框架。或者您可以在客户端 class 中创建一个方法来请求信息(中介模式)。

我喜欢第二个选项,但它意味着更多的工作:

class Client{
    private String name;
    ...
   public void publishInfo(ClientInfo c){
      c.setName(name);
      ...
    }
}

class ClientInfo{
    private String name;
    //GETTERS
    //SETTERS
}

Allen Holub 的文章(您提到的那篇)是完全正确的,您不应该索取数据,至少在您做 Object-Orientation 的时候。不,展示东西不是打开 object.

的有效借口

如果您有 Book,只需要求 Book 显示它自己!使用 JTextFieldJTable 或其他什么都不重要。当然,根据您的要求,您可以这样做:

public final class Book {
    ...
    JComponent display() {
        ...
    }
}

Object-Orientation 的重点当然是您正在尝试本地化更改(尽可能限制为一个 class)。做到这一点的唯一方法是将依赖于相同事物的功能本地化为(最好)相同的 class。也称为递增 "cohesion".

所以现在,如果 Book 内部发生变化,所有的东西,包括 Book 的显示方式都在 Book 本身,所以没有必要 "hunt" 用于使用 Book.

的代码

现在,对于这不是 "clean" 的答案,因为您将表示代码与 "business logic" 混合在一起。值得注意的是,不将 presentation 与 "business logic" 混合的整个想法来自早期,当时我们仍然认为 presentation 可能是 "remote" 到 "business objects",其中 "business objects" 可能被多个应用程序用于不同的事情。 IE。 multi-tier 设计。 YAGNI。大多数时候,没有真正的理由在单个应用程序中设置人为的技术边界。如果 Book 知道它是 GUI 应用程序的一部分并没有什么坏处,并且有真正的好处(可维护性)。

编辑:这是 `display() 方法的详细外观,显示标题和作者(Swing 的伪代码):

public final class Book {
    private final String title;
    private final List<Author> authors;
    ...
    public JComponent display() {
        JPanel bookPanel = new JPanel();
        bookPanel.add(new JLabel(title));
        JList authorsList = new JList(); // Or similar
        for (Author author: authors) {
            authorsList.add(author.display());
        }
        bookPanel.add(authorsList);
        return bookPanel;
    }
}

然后您可以简单地 add() 将该组件添加到您想要在其中显示书籍的任何 swing 容器。