3

我想在不使用 ORM(如 Hibernate)的情况下将对象保存并加载到数据库中。

可以说我有以下课程:

public class Person {
    private int age;

    public void birthday(){
        age++;
    }
 }

该类不提供get-method,因此内部状态(年龄)被封装。

如果我想保存对象,我需要一个 getter 方法来执行以下操作:

insert into TABLE_PERSON (id, age) vales (1, person.getAge());

反过来,我需要一个 setter 方法来加载对象:

int age = "Select age FROM Person";
person.setAge(age);

但我不想打破封装(通过实现额外的 setter 和 getter 方法)只是为了保存和加载对象。

有没有可能做到这一点?也许某种模式(纪念品?)或最佳实践?

先感谢您!

4

5 回答 5

2

Allen Holub 写了几篇关于这个主题的文章。他提出了一个 Builder 和他称之为 Reverse Builder 模式的东西。

在您的情况下,它的工作方式是 Person 将负责生成自身的表示。也就是说,您定义了一个 PersonImporter 和 PersonExporter 接口来将数据移入和移出 Person 对象。这些类基本上是 Person 设计的一部分。所以:

interface PersonImporter {

    public int getAge();

    public String getId();
}

interface PersonExporter {

    public void setDetails(String id, int age);

}

class Person {

    private int age;
    private String id;

    public Person(PersonImporter importer) {
        age = importer.getAge();
        id = importer.getId();
    }

    public void export(PersonExporter exporter) {
        exporter.setDetails(id, age);
    }

}

这并没有完全消除 getter 和 setter,而是使用接口控制它。

Holub的文章

于 2015-02-12T21:37:49.207 回答
2

你提到了纪念品。Grand 记录了一个名为Snapshot的变体。这是 UML 类图:

快照模式

Person将是Originator模式中的。

您可以将 Memento 实例转储到数据库中的二进制对象。

请注意,Memento 是 Originator 的内部类。createMemento/setMemento 是一种单一的 get/set,如果你是一个纯粹主义者,它可能会破坏封装。但是,调用中使用的信息包(Memento)是一个没有方法Originator's的接口,因此可以保证状态的封装。如果您正确映射它,这甚至可能适用于 ORM。

当然,为了避免获取/设置,这似乎需要做很多工作。您的人物/年龄示例不太现实(不是一个很好的人物模型)。暴露一个人的年龄或出生日期是很正常的,并且暴露该属性以持久化对象是可以的。封装并不意味着不透露任何东西。这意味着不要暴露太多细节。

例如,让我们不要使用age,而是使用Person.birthday. 这可以在内部存储为 YYYY-MM-DD 格式的字符串或使用 Date 对象。这样的细节不会被暴露(它会被封装)。这样做也是为了您可以更改它而不影响您班级的客户。您隐藏的任何内容都可以更改,而不会对客户产生负面影响。

通过暴露一个人的生日,你说“我冒着这个人永远有生日的风险”。该部分是暴露的,因此很难在不破坏客户端的情况下进行更改。

评论后编辑

公共方法(例如,saveloadPerson可以处理保存/加载数据库操作。他们将有权访问私有字段 ( age) 并可以完成工作。你说你没有使用 ORM,所以你自己做。

于 2014-07-24T03:18:40.183 回答
0

这是我的想法,可能并不完美。

封装是为了隐藏数据。也许,您只是不希望有人为age属性设置错误的值。

也许您可以引入一个包装类,供外部代码使用,并且只允许该类使用您的Person类。

如果您使用public包装类创建一个文件,可以说 PersonWrapper,它提供了年龄的 getter 和 setter。但是这些 getter 和 setter 可以具有您想要的验证逻辑,例如可以为哪些值设置age,谁可以等。在同一个文件中,Person类可以定义为private但使用普通的 getter 和 setter 作为age参数。您PersonWrapper应该只Person在某些预定义条件下使用类 getter 和 setter。

这样你也许能够有更好的封装。

于 2014-07-23T21:30:54.100 回答
0

这里的一种方法是使用映射器类。创建一个将类映射到表的 PersonMAP,并将所有数据库操作封装在该类中。

于 2014-07-24T06:23:44.820 回答
-2

我真的不明白使用 getter/setter 是如何破坏封装的。getter 和 setter 尊重封装。事实上,它们是实现它的一种手段。

于 2014-07-23T22:05:20.127 回答