【问题标题】:Ensuring UML constraints in Java?确保 Java 中的 UML 约束?
【发布时间】:2013-06-07 13:08:16
【问题描述】:

假设我的应用程序设计有两个类:PersonCompany。另外假设我定义了一个UML图,它定义了PersonCompany之间的一对多关系:每个Person对象必须恰好属于一个Company,一个Company可以包含许多@987654328 @s.

有哪些最佳实践可以确保这个简单的约束始终成立,即永远不会有一个时间点Person 对象包含在多个Company 中?我想到了三种方法:

  1. 拥有完美、无错误的代码,永远不会违反我的任何约束。然而,作为一个现实主义者,我知道这很难或不可能,尤其是随着约束数量的增加。

  2. 实现手动检查每个约束的ensureCorrectness() 方法。在本例中,它将遍历所有Persons,并确保恰好一个Company 包含Person。如果没有,它会打印一个错误。我会经常调用这个方法。

  3. 使用例如 Hibernate 来定义数据库模式并将数据存储到数据库中。在模式中,我可以定义一个约束来匹配我的 UML 图中的约束。然后,每当我将数据持久化到数据库中时,Hibernate 将检查所有约束并在出现问题时打印错误。

但我不禁想知道在 Java 中是否有另一种更简洁的方法来执行此操作,它不依赖于 (1) 完美、(2) 手动验证或 (3) 关系数据库。是否有一个库或框架允许我在代码中指定注释,类似于:

@OneToMany(Person, Company)

或者更具体地说:

@OneToMany(Person, Company.persons)

假设Company 类有一个List<Person> persons 成员变量。

如果我想确保一个人的社会安全号码在所有Persons 中是唯一的,我可以说:

@Unique(Person.SSN)

Java 有类似的东西吗?

【问题讨论】:

    标签: java model uml constraints


    【解决方案1】:

    公司与个人之间的关系并不难。制作例如Company 中包含 Person 元素的列表。您必须手动确保的一件事是该列表不包含单个 Person 的多个实例。

    反之则更难。您必须手动检查这一点(每个列表不包含同一 Person 的多个实例)。但是你可以把它和之前的限制结合起来:

    所有人员列表的长度应与所有具有唯一人员的列表的长度相同。

    我对数据库了解不多,但我会选择第二个选项 (ensureCorrectNess) 来检查上面的手动限制。

    【讨论】:

    • 所以您是说 Java 中没有这样的框架或库可以自动执行此操作,我应该只实现我在原始问题中列出的选项 (2)?
    • 我不太了解Java,但我不知道有这样的库。
    【解决方案2】:

    我会选择#1,结合封装。这样,必须 100% 无错误的代码量非常少

    public class Company {
        private List<Person> persons = new ArrayList<>();
        private List<Person> publicPerson = Collections.unmodifiableList(persons);
    
        public List<Person> getPersons { return publicPersons; }
    
        public void addPerson(Person p) {
             ... ensure p is removed from old company
             p.setCompany(this);
             persons.add(p);
        }
    
    }
    
    public class Person {
        private Company company;
        /* pkg-private */ setCompany(Company company) {
            this.company = company;
        }
        public Company getCompany() {
            return company;
        }
    }
    

    小心,这段代码不是线程安全的!

    请注意,如果您保存到数据库,hibernate 只会检查约束。由于缓存,可能会出现不一致的情况。

    【讨论】:

    • 这个解决方案的缺点是,类似于 eternay 的解决方案,没有办法将所有约束隔离到一个地方:它们将分散在代码库中。如果我有 300 个限制条件,那么在一个地方查看/更改它们就不容易了。
    • 约束在它们所属的模型类中。你可以看看 JavaFX 的属性,但是你会得到一些开销。这是一个普遍的问题:由于 Java 的静态特性,如果您想要集中配置,最终会在运行时进行字节码操作。
    • 我猜你对模型类中的约束是正确的,但我仍然认为写@OneToMany(Person, Company.persons) 之类的东西会更容易,而不是为我实现这个检查的代码。也许我是一个梦想家。顺便说一句,我看不出 JavaFX 属性如何帮助确保对象之间的多对一关系,但我会进行更深入的调查。
    • 注释方法的问题是您必须在编译或加载时重写所有字段访问字节码。我不知道 jfx 属性有多强大,但你可以用绑定做一些事情。
    【解决方案3】:

    我会像在 Java 中那样实现它:

    public class Company {
        Set<Person> persons;
        ...
        public void addPerson(Person person) {
            if (person.getCompany() != this) { // Avoiding an infinite loop between addPerson() and setCompany()
                person.setCompany(this);
                persons.add(person);
            }
        }
        public boolean removePerson(Person person) {
            return persons.remove(person);
        }
        ...
    }
    
    public class Person {
        Company company;
        public Person(Company company) {
            this.company = company;
        }
        public void setCompany(Company company) {
            if (this.company != null) {
                this.company.remove(this);
            }
            this.company = company;
            company.addPerson(this);
        }
        ...
    }
    

    在代码中,Person 不能有多个Company,而Company 有一个Persons 列表。使用Person(Company) 构造函数,Person 至少分配了一家公司。

    编辑:要修改Set(不重复),您必须通过调用Person.setCompany() 方法的addPerson() 方法。此方法将从先前的Company 列表中删除Person,并将其添加到新的Company 列表中。

    setCompany() 中,您必须调用addPerson(),因为程序员可以直接将Person 分配给Company,而无需先调用addPerson()

    【讨论】:

    • 但是如何阻止Person 对象出现在两个Companypersons 列表中?
    • 所以基本上你是说Java中没有这样的框架或库来自动检查这些类型的约束,最好的解决方案是在整个代码中加入约束逻辑?那么,如果我有 300 个这样的约束,就没有办法将它们全部集中在一个地方吗?
    • 我了解您的问题,但我不知道有任何框架可以控制这些类型的约束。不代表它不存在,因为我不知道所有现有的框架,有这么多......
    【解决方案4】:

    首先,您可以通过将数据库中的 col 设置为不为 null 并且客户 ID 是唯一的,从而非常轻松地在数据库中配置所有这些。 您可以在前后使用触发器来确保将数据删除或添加到数据库中。

    第二个选项,您可以通过使用哈希映射来设置 java 类上的所有数据库以包含数据。

    在我看来,第一个选项更容易..

    【讨论】:

    • 感谢您的回复,但我特意要求提供不依赖底层数据库的解决方案。我正在寻找纯 Java 解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-17
    • 2022-11-02
    相关资源
    最近更新 更多