保存并加载对象而不破坏封装

时间:2014-07-23 21:21:01

标签: java database design-patterns encapsulation memento

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

假设我有以下课程:

public class Person {
    private int age;

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

此类不提供get方法,因此封装了内部状态(age)。

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

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

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

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

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

有可能这样做吗?也许是某种模式(纪念品?)或最佳实践?

提前谢谢!

5 个答案:

答案 0 :(得分:2)

艾伦·霍尔布(Allen Holub)就这一主题写了几篇文章。他提出了一个Builder,他称之为Reverse Builder模式。

在你的情况下它将起作用的方式一个人将负责生成自己的表示。也就是说,您定义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's Article

答案 1 :(得分:0)

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

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

也许你可以介绍一个包装类,它由外部代码使用,只允许该类使用你的Person类。

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

通过这种方式,您可以获得更好的封装。

答案 2 :(得分:0)

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

Snapshot pattern

Person将是模式中的Originator

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

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

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

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

通过揭露一个人的生日,你说“我冒着人将永远生日的风险。”该部分被曝光,因此在不破坏客户的情况下很难改变。

评论后编辑

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

答案 3 :(得分:0)

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

答案 4 :(得分:-2)

我真的不知道如何使用getter / setter打破封装。 Getters和setters尊重封装。事实上,他们是实现目标的手段。

相关问题