Проверьте инварианты в отображенных в спящем классе

Одной из проблем использования Hibernate является то, что управляемые классы должны иметьконструктор по умолчанию, Проблема в том, что нет явной точки, где класс инициализируется и инварианты могут быть проверены.

Если у класса есть инварианты, которые зависят от нескольких свойств, дизайн класса становится сложным. Позволять'Начнем с гипотетического дизайна зеленого поля:

public class A { 
    private int x; 
    private int y; 

    public A(int x, int y) { 
        this.x = x; 
        this.y = y; 
        checkInvariants(this.x, this.y); 
    } 

    private void checkInvariants(int x, int y) { 
        if (x + y « 0) throw new IllegalArgumentException(); 
    } 
}

Это базовая реализация, которая не соответствует требованиям гибернации. Инвариант проверяется в конструкторе. (Содержание метода checkInvariants () не имеет значения 'Представлены только для иллюстрации того, что инварианты класса могут зависеть от более чем одного свойства.)

Класс можно использовать следующим образом:

new A(0, 0); 
new A(-1, 0); //invalid 

Чтобы удовлетворить требования гибернации, одним из обходных путей является добавлениезакрытый конструктор по умолчанию а такжеиспользовать доступ к полю, (Я опустил отображения спящего режима.)

public class H { 
    int x; 
    int y; 

    public H(int x, int y) { 
        this.x = x; 
        this.y = y; 
        checkInvariants(this.x, this.y); 
    } 

    H(){} 

    private void checkInvariants(int x, int y) { 
        if (x + y « 0) throw new IllegalArgumentException(); 
    } 
} 

Это имеет два основных недостатка:начинаем реализовывать код, которыйзависит от клиента (Спящий режим). В идеале класс не знает своих вызывающих. * Особая проблема с этим обходным решением заключается в том, что экземпляры, инициированные hibernate,не проверено если встретить инварианты. Вы'доверять данным, загруженным из базы данных, что проблематично. Даже если ваше приложение является единственным, использующим эту конкретную схему базы данных, всегда есть возможность специальных изменений со стороны администраторов.

Второй обходной путь заключается впроверить инварианты в коде пользователя:

public class I { 
    private int x; 
    private int y; 

    public I() {} 

    public void checkInvariants() { 
        if (x + y « 0) throw new IllegalArgumentException(); 
    } 

    public void setX(int x){ 
        this.x = x; 
    } 

    public void setY(int y){ 
        this.y = y; 
    } 
} 

I i = new I(); 
i.setX(-1); 
i.setY(0); 
i.checkInvariants(); 

Очевидно, это делает код пользователяболее сложный а такжеподверженные ошибки, Этот дизайн не соответствует ожиданиям того, что экземпляр является согласованным после создания и остается согласованным после каждого изменения состояния (вызова метода). Каждый пользователь должен проверять инварианты для каждого создаваемого им экземпляра (возможно, косвенно с помощью hibernate).

Есть ли лучшее решение этой проблемы:

не слишком сложныйбез явных знаний о своих пользователяхбез зависимости от спящего фреймворка?

Я полагаю, что некоторые ограничения необходимо ослабить, чтобы найти прагматичное решение. Единственным жестким ограничением является отсутствие зависимости от каркаса гибернации. (Специальный код Hibernate вне доменных объектов в порядке).

(Просто из любопытства: есть ли структура ORM, которая поддерживает «конструктор инъекций »?)

Ответы на вопрос(3)

Ваш ответ на вопрос