20. Przykłady
Aplikacja zarządzająca POI
● POI – ang. Point of Interest
● Grupa
● Podgrupa
● POI: nazwa, położenie (x,y)
● Użytkownik z prawami dostępu
●
Grupa
Podgrupa
POI
24. Mainstreamowa architektura
- nasz model to encje hibernetowe
- logika biznesowa zamknięta w warstwie
serwisowej
- kod zapytań do bazy danych przez obiekty typu
DAO
25. Mainstreamowa architektura
- nasz model to encje hibernetowe
- logika biznesowa zamknięta w warstwie
serwisowej
- kod zapytań do bazy danych przez obiekty typu
DAO
- encje wykorzystywane w warstwie widoku
61. Encja na widoku, i co z tego?
●
Ważne pytanie dla encji – czy już zna Cię
PersistenceContext?
62. Encja na widoku, i co z tego?
●
●
Ważne pytanie dla encji – czy już zna Cię
PersistenceContext?
Algorytm tworzenia widoku jak i sama jego
struktura oparta o encje
63. Encja na widoku, i co z tego?
●
●
Ważne pytanie dla encji – czy już zna Cię
PersistenceContext?
Algorytm tworzenia widoku jak i sama jego
struktura oparta o encje
Widok mocno związany ze strukturą bazy
64. Encja na widoku, i co z tego?
●
●
Ważne pytanie dla encji – czy już zna Cię
PersistenceContext?
Algorytm tworzenia widoku jak i sama jego
struktura oparta o encje
Widok mocno związany ze strukturą bazy
Skostniałość - dashboard
69. Encja na widoku, i co z tego?
●
●
Ważne pytanie dla encji – czy już zna Cię
PersistenceContext?
Algorytm tworzenia widoku jak i sama jego
struktura oparta o encje
Widok mocno związany ze strukturą bazy
Skostniałość – dashboard
70. Encja na widoku, i co z tego?
●
●
Ważne pytanie dla encji – czy już zna Cię
PersistenceContext?
Algorytm tworzenia widoku jak i sama jego
struktura oparta o encje
●
Widok mocno związany ze strukturą bazy
Skostniałość – dashboard
LazyInitializationException
71. PoiEntity poi = poiService.find(poiId);
poi.getConnectedPois();
72. PoiEntity poi = poiService.find(poiId);
poi.getConnectedPois();
73. PoiEntity poi = poiService.find(poiId);
poi.getConnectedPois();
74. PoiEntity poi = poiService.find(poiId);
poi.getConnectedPois();
LazyInitializationException
94. List<PoiEntity> pois =
poiService.findForUser(user);
for(PoiEntity p : pois) {
poi.getConnectedPois();
}
select * from t_pois where user_id = :uId;
select * from t_pois where ...
select * from t_pois where ...
select * from t_pois where ...
select * from t_pois where ...
select * from t_pois where ...
95. List<PoiEntity> pois =
poiService.findForUser(user);
for(PoiEntity p : pois) {
poi.getConnectedPois();
}
select * from t_pois where user_id = :uId;
select * from t_pois where ...
select * from t_pois where ...
select * from t_pois where ...
select * from t_pois where ...
select * from t_pois where ...
96. Encja na widoku, i co z tego?
●
●
Ważne pytanie dla encji – czy już zna Cię
PersistenceContext?
Algorytm tworzenia widoku jak i sama jego
struktura oparta o encje
●
Widok mocno związany ze strukturą bazy
Skostniałość – dashboard
LazyInitializationException
97. Encja na widoku, i co z tego?
●
●
Ważne pytanie dla encji – czy już zna Cię
PersistenceContext?
Algorytm tworzenia widoku jak i sama jego
struktura oparta o encje
Widok mocno związany ze strukturą bazy
Skostniałość – dashboard
●
LazyInitializationException
●
Testowalność
98. Encja na widoku, i co z tego?
●
●
Ważne pytanie dla encji – czy już zna Cię
PersistenceContext?
Algorytm tworzenia widoku jak i sama jego
struktura oparta o encje
Widok mocno związany ze strukturą bazy
Skostniałość – dashboard
●
LazyInitializationException
●
Testowalność
"Testy już przechodzą, muszę jeszcze tylko przeklikać"
108. Warstwa aplikacji – organizacja
●
Jest abstrakcją aplikacji
●
Aplikacja to zbiór funkcjonalności
109. Warstwa aplikacji – organizacja
●
Jest abstrakcją aplikacji
●
Aplikacja to zbiór funkcjonalności
●
Funkcjonalności zdefiniowane (w ten czy inny
sposób)
110. Warstwa aplikacji – organizacja
●
Jest abstrakcją aplikacji
●
Aplikacja to zbiór funkcjonalności
●
●
Funkcjonalności zdefiniowane (w ten czy inny
sposób)
Z natury bardzo 'proceduralne'
114. Warstwa aplikacji – organizacja
●
Jest abstrakcją aplikacji
●
Aplikacja to zbiór funkcjonalności
●
●
Funkcjonalności zdefiniowane (w ten czy inny
sposób)
Z natury bardzo 'proceduralne'
115. Warstwa aplikacji – organizacja
●
Jest abstrakcją aplikacji
●
Aplikacja to zbiór funkcjonalności
●
●
●
Funkcjonalności zdefiniowane (w ten czy inny
sposób)
Z natury bardzo 'proceduralne'
Przełożenie tych definicji na klasy, które
definiują dany konkretny wycinek
funkcjonalności
116. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
117. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
public interface UCListingPoiDetails {
List<PoiDto> list(Long subgroupId);
boolean canList(Long subgroupId);
}
118. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
public interface UCListingPoiDetails {
List<PoiDto> list(Long subgroupId);
boolean canList(Long subgroupId);
}
public class PoiDto {
private final String name;
private final Coordinates coordinates;
private final List<PoiDto> connectedPois;
}
119. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
public interface UCListingPoiDetails {
List<PoiDto> list(Long subgroupId);
boolean canList(Long subgroupId);
}
@Data
public class PoiDto {
private final String name;
private final Coordinates coordinates;
private final List<PoiDto> connectedPois;
}
120. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
public interface UCListingPoiDetails {
List<PoiDto> list(Long subgroupId);
boolean canList(Long subgroupId);
}
121. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
public interface UCListingPoiDetails {
List<PoiDto> list(Long subgroupId);
boolean canList(Long subgroupId);
}
122. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
public interface UCListingPoiDetails {
List<PoiDto> list(Long subgroupId);
ActionPossible canList(Long subgroupId);
}
public interface ActionPossible {
boolean isPossible();
String explainImpossible();
}
123. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
public class SubGroupPoisListPanel {
@Autowired private UCListingPoiDetails uc;
...
public SubGroupPoisListPanel(Long subgroupId) {
ActionPossible canList = uc.canList();
if(canList.isPossible() {
add(createList(uc.list(subgroupId));
} else {
String reason = canList.explainImpossible();
add(new Label("info", reason);
}
}
124. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
public class SubGroupPoisListPanel {
@Autowired private UCListingPoiDetails uc;
...
public SubGroupPoisListPanel(Long subgroupId) {
ActionPossible canList = uc.canList();
if(canList.isPossible() {
add(createList(uc.list(subgroupId));
} else {
String reason = canList.explainImpossible();
add(new Label("info", reason);
}
}
125. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
public class SubGroupPoisListPanel {
@Autowired private UCListingPoiDetails uc;
...
public SubGroupPoisListPanel(Long subgroupId) {
ActionPossible canList = uc.canList();
if(canList.isPossible() {
add(createList(uc.list(subgroupId));
} else {
String reason = canList.explainImpossible();
add(new Label("info", reason);
}
}
126. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
public class SubGroupPoisListPanel {
@Autowired private UCListingPoiDetails uc;
...
public SubGroupPoisListPanel(Long subgroupId) {
ActionPossible canList = uc.canList();
if(canList.isPossible() {
add(createList(uc.list(subgroupId));
} else {
String reason = canList.explainImpossible();
add(new Label("info", reason);
}
}
127. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
public class SubGroupPoisListPanel {
@Autowired private UCListingPoiDetails uc;
...
public SubGroupPoisListPanel(Long subgroupId) {
ActionPossible canList = uc.canList();
if(canList.isPossible() {
add(createList(uc.list(subgroupId));
} else {
String reason = canList.explainImpossible();
add(new Label("info", reason);
}
}
128. ●
Jako użytkownik z prawem 'szczegóły poi' mogę wylistować
wszystkie POI w danej podgrupie
widzę nazwę, położenie oraz listę innych POI, z którym dane POI
jest powiązane
public class SubGroupPoisListPanel {
@Autowired private UCListingPoiDetails uc;
...
public SubGroupPoisListPanel(Long subgroupId) {
ActionPossible canList = uc.canList();
if(canList.isPossible() {
add(createList(uc.list(subgroupId));
} else {
String reason = canList.explainImpossible();
add(new Label("info", reason);
}
}
129. ●
Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę
zmieniać tylko i wyłącznie wartość położenia danego POI
public interface UCUpdatingPoiCoordinates {
void update(Long poiId, Coordinates c);
ActionPossible canUpdate();
ActionPossible canUpdateWithArgs(
Long poiId,
Coordinates c);
}
130. ●
Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę
zmieniać tylko i wyłącznie wartość położenia danego POI
@Autowired private UCUpdatingPoiCoordinates uc;
Button update = new Button("update") {
public void onSubmit() {
ActionPossible withArgs =
uc.canUpdateWithArgs(poiId, coords);
if(withArgs.isPossible())
uc.update(poiId, coords)
else
userSession.warn(withArgs.explainImpossible());
}
}
update.setVisible(uc.canUpdate().isPossible());
131. ●
Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę
zmieniać tylko i wyłącznie wartość położenia danego POI
@Autowiredprivate UCUpdatingPoiCoordinates uc;
Button update = new Button("update") {
public void onSubmit() {
ActionPossible withArgs =
uc.canUpdateWithArgs(poiId, coords);
if(withArgs.isPossible())
uc.update(poiId, coords)
else
userSession.warn(withArgs.explainImpossible());
}
}
update.setVisible(uc.canUpdate().isPossible());
132. ●
Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę
zmieniać tylko i wyłącznie wartość położenia danego POI
@Autowired private UCUpdatingPoiCoordinates uc;
Button update = new Button("update") {
public void onSubmit() {
ActionPossible withArgs =
uc.canUpdateWithArgs(poiId, coords);
if(withArgs.isPossible())
uc.update(poiId, coords)
else
userSession.warn(withArgs.explainImpossible());
}
}
update.setVisible(uc.canUpdate().isPossible());
133. ●
Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę
zmieniać tylko i wyłącznie wartość położenia danego POI
@Autowired private UCUpdatingPoiCoordinates uc;
Button update = new Button("update") {
public void onSubmit() {
ActionPossible withArgs =
uc.canUpdateWithArgs(poiId, coords);
if(withArgs.isPossible())
uc.update(poiId, coords)
else
userSession.warn(withArgs.explainImpossible());
}
}
update.setVisible(uc.canUpdate().isPossible());
134. ●
Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę
zmieniać tylko i wyłącznie wartość położenia danego POI
@Autowired private UCUpdatingPoiCoordinates uc;
Button update = new Button("update") {
public void onSubmit() {
ActionPossible withArgs =
uc.canUpdateWithArgs(poiId, coords);
if(withArgs.isPossible())
uc.update(poiId, coords)
else
userSession.warn(withArgs.explainImpossible());
}
}
update.setVisible(uc.canUpdate().isPossible());
135. ●
Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę
zmieniać tylko i wyłącznie wartość położenia danego POI
@Autowired private UCUpdatingPoiCoordinates uc;
Button update = new Button("update") {
public void onSubmit() {
ActionPossible withArgs =
uc.canUpdateWithArgs(poiId, coords);
if(withArgs.isPossible())
uc.update(poiId, coords)
else
userSession.warn(withArgs.explainImpossible());
}
}
update.setVisible(uc.canUpdate().isPossible());
136. ●
Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę
zmieniać tylko i wyłącznie wartość położenia danego POI
@Autowired private UCUpdatingPoiCoordinates uc;
Button update = new Button("update") {
public void onSubmit() {
...
}
}
update.setVisible(uc.canUpdate().isPossible());
137. ●
Jako użytkownik z prawem 'aktualizator_lokalizacji' mogę
zmieniać tylko i wyłącznie wartość położenia danego POI
@Autowired private UCUpdatingPoiCoordinates uc;
Button update = new Button("update") {
public void onSubmit() {
...
}
}
ActionPossible canUpdate = uc.canUpdate();
update.setEnabled(canUpdate.isPossible());
if(!canUpdate.isPossible()) {
String reason = canUpdate.explainImpossible();
update.add(new TooltTip(reason));
}
138. Problem jednego stack'a
ID
Nazwa
Data utworzenia
Stan
1
Konkurs 1
05.07.2013
Nowy
2
Konkurs 2
01.06.2013
Zamknięty
3
Konkurs 3
15.06.2013
Uruchomiony
139. Problem jednego stack'a
@Entity public class Contest {
@Id private Long id;
private String name;
private LocalDate creationDate;
@Enumerated private State state;
ID
Nazwa
Data utworzenia
Stan
1
Konkurs 1
05.07.2013
Nowy
2
Konkurs 2
01.06.2013
Zamknięty
3
Konkurs 3
15.06.2013
Uruchomiony
140. Problem jednego stack'a
@Entity public class Contest {
@Id private Long id;
private String name;
private LocalDate creationDate;
@Enumerated private State state;
public Contest(String name) {
this.name = name;
this.creationDate = new LocalDate();
this.state = State.NOWY;
}
ID
Nazwa
Data utworzenia
Stan
1
Konkurs 1
05.07.2013
Nowy
2
Konkurs 2
01.06.2013
Zamknięty
3
Konkurs 3
15.06.2013
Uruchomiony
141. Problem jednego stack'a
@Entity public class Contest {
...
public void start() { .. }
public void close() { .. }
public boolean isAnnual() { .. }
}
ID
Nazwa
Data utworzenia
Stan
1
Konkurs 1
05.07.2013
Nowy
2
Konkurs 2
01.06.2013
Zamknięty
3
Konkurs 3
15.06.2013
Uruchomiony
142. Problem jednego stack'a
@Entity public class Contest {
...
public void start() { .. }
public void close() { .. }
public boolean isAnnual() { .. }
}
ID
Nazwa
Data utworzenia
Stan
1
Konkurs 1
05.07.2013
Nowy
2
Konkurs 2
01.06.2013
Zamknięty
3
Konkurs 3
15.06.2013
Uruchomiony
143. Problem jednego stack'a
@Entity public class Contest {
...
public void start() { .. }
public void close() { .. }
public boolean isAnnual() { .. }
}
okej..
Chce taki panel
ID
Nazwa
Data utworzenia
Stan
1
Konkurs 1
05.07.2013
Nowy
2
Konkurs 2
01.06.2013
Zamknięty
3
Konkurs 3
15.06.2013
Uruchomiony
144. Problem jednego stack'a
@Entity public class Contest {
...
public void start() { .. }
public void close() { .. }
public boolean isAnnual() { .. }
public String getName() {..}
public LocalDate getCreationDate() {..}
public State getState() {..}
}
ID
Nazwa
Data utworzenia
Stan
1
Konkurs 1
05.07.2013
Nowy
2
Konkurs 2
01.06.2013
Zamknięty
3
Konkurs 3
15.06.2013
Uruchomiony
149. Rozwiązania
●
CQRS
●
CQRS dla ubogich :)
●
●
●
Rozróżnienie na Command i Query
Obiekty modelu (User, Poi, Subgroup) i serwisy
(UserCreator) używane do obsługi poleceń
Specjalne serwisy typu Query używane do obsługi
zapytań
150. Rozwiązania
●
CQRS
●
CQRS dla ubogich :)
●
●
●
●
Rozróżnienie na Command i Query
Obiekty modelu (User, Poi, Subgroup) i serwisy
(UserCreator) używane do obsługi poleceń
Specjalne serwisy typu Query używane do obsługi
zapytań
Query niczym Wyrocznia
161. @Service
public class DefaultUCUpdatingPoiCoordinates
implements UCUpdatingPoiCoordinates {
public ActionPossible canUpdate() {..}
ActionPossible canUpdateWithArgs(Long poiId,
Coordinates c) {..}
public void update(Long poiId, Coordinates c) {
checkThat(canUpdate());
}
}
162. @Service
public class DefaultUCUpdatingPoiCoordinates
implements UCUpdatingPoiCoordinates {
public ActionPossible canUpdate() {..}
ActionPossible canUpdateWithArgs(Long poiId,
Coordinates c) {..}
public void update(Long poiId, Coordinates c) {
checkThat(canUpdate());
checkArguments(canUpdateWithArgs(poiId,c));
}
}
163. @Service
public class DefaultUCUpdatingPoiCoordinates
implements UCUpdatingPoiCoordinates {
@Autowired PoiFinder poiFinder;
public ActionPossible canUpdate() {..}
ActionPossible canUpdateWithArgs(Long poiId,
Coordinates c) {..}
public void update(Long poiId, Coordinates c) {
checkThat(canUpdate());
checkArguments(canUpdateWithArgs(poiId,c));
poiFinder.find(poiId).updateCoordinates(c);
}
}
164. @Service
public class DefaultUCUpdatingPoiCoordinates
implements UCUpdatingPoiCoordinates {
@Autowired PoiFinder poiFinder;
@Autowired MailSender mailSender;
public ActionPossible canUpdate() {..}
ActionPossible canUpdateWithArgs(Long poiId,
Coordinates c) {..}
public void update(Long poiId, Coordinates c) {
checkThat(canUpdate());
checkArguments(canUpdateWithArgs(poiId,c));
poiFinder.find(poiId).updateCoordinates(c);
mailSender.send(createContent());
}
168. Warstwa Application
●
przejrzyste API zorientowane na przypadki
użycia
●
testowalność
●
"głupi" widok, wiele warstw prezentacji
●
wejście w projekt
169. Warstwa Application
●
przejrzyste API zorientowane na przypadki
użycia
●
testowalność
●
"głupi" widok, wiele warstw prezentacji
●
wejście w projekt
●
polyglot programmer
170. Warstwa Application
●
przejrzyste API zorientowane na przypadki
użycia
●
testowalność
●
"głupi" widok, wiele warstw prezentacji
●
wejście w projekt
●
polyglot programmer
●
chodliwe funkcjonalności niemalże za darmo
171. Warstwa Application
●
przejrzyste API zorientowane na przypadki
użycia
●
testowalność
●
"głupi" widok, wiele warstw prezentacji
●
wejście w projekt
●
polyglot programmer
●
chodliwe funkcjonalności niemalże za darmo
●
Excel export
172. Warstwa Application
●
przejrzyste API zorientowane na przypadki
użycia
●
testowalność
●
"głupi" widok, wiele warstw prezentacji
●
wejście w projekt
●
polyglot programmer
●
chodliwe funkcjonalności niemalże za darmo
●
Excel export
●
Aktywność użytkownika
178. Obiekty Modelu
●
Encja jest obiektem reprezentującym model
●
Gettery/settery defacto wymagane
●
Metody typu add, remove
179. Obiekty Modelu
●
Encja jest obiektem reprezentującym model
●
Gettery/settery defacto wymagane
●
Metody typu add, remove
●
Metody "biznesowe" (run(), isRunning(),
close())
180. Obiekty Modelu
●
Encja jest obiektem reprezentującym model
●
Gettery/settery defacto wymagane
●
Metody typu add, remove
●
●
Metody "biznesowe" (run(), isRunning(),
close())
Troche bardziej skomplikowana encja może
mieć nawet i kilka tysięcy linii kodu
181. Obiekty Modelu
●
Encja jest obiektem reprezentującym model
●
Gettery/settery defacto wymagane
●
Metody typu add, remove
●
●
●
Metody "biznesowe" (run(), isRunning(),
close())
Troche bardziej skomplikowana encja może
mieć nawet i kilka tysięcy linii kodu
Encja nie jest ani strukturą danych, ani
obiektem (metoda canRun() obok getState())
184. Pomysł...
●
Niech encja reprezentuje tylko i wyłącznie
schemat relacyjny w świecie obiektowym
●
Encje jedynie jako reprezentacje tabel
●
Encja anemiczna
187. Pomysł...
@Entity
public class UserEntity {
@Id private Long id;
private String login;
@OneToMany private Set<RoleEntity> roles;
Long getId() {..}, void setId(Long id) {..}
Long getLogin() {..}, void setLogin(String lo) {..}
Set<RoleEntity> getRoles() {..},
void setRoles(Set<RoleEntity> roles) {..}
}
188. Pomysł...
@Entity
public class UserEntity {
@Id private Long id;
private String login;
@OneToMany private Set<RoleEntity> roles;
Long getId() {..}, void setId(Long id) {..}
Long getLogin() {..}, void setLogin(String lo) {..}
Set<RoleEntity> getRoles() {..},
void setRoles(Set<RoleEntity> roles) {..}
void addRole(RoleEntity role) {..}
void removeRole(RoleEntity role) {..}
}
189. Pomysł...
@Entity
@Data
public class UserEntity {
@Id private Long id;
private String login;
@OneToMany private Set<RoleEntity> roles;
void addRole(RoleEntity role) {..}
void removeRole(RoleEntity role) {..}
}
190. Pomysł - obiekt biznesowy
●
Niech encja reprezentuje tylko i wyłącznie
schemat relacyjny w świecie obiektowym
●
Encje jedynie jako reprezentacje tabel
●
Encja anemiczna
191. Pomysł - obiekt biznesowy
●
Niech encja reprezentuje tylko i wyłącznie
schemat relacyjny w świecie obiektowym
●
Encje jedynie jako reprezentacje tabel
●
Encja anemiczna
●
Obiekt biznesowy – reprezentant modelu
192. Pomysł - obiekt biznesowy
●
Niech encja reprezentuje tylko i wyłącznie
schemat relacyjny w świecie obiektowym
●
Encje jedynie jako reprezentacje tabel
●
Encja anemiczna
●
Obiekt biznesowy – reprezentant modelu
na początku można o nim myśleć jako wrapper na
encję
193. Pomysł - obiekt biznesowy
●
Niech encja reprezentuje tylko i wyłącznie
schemat relacyjny w świecie obiektowym
●
Encje jedynie jako reprezentacje tabel
●
Encja anemiczna
●
Obiekt biznesowy – reprezentant modelu
na początku można o nim myśleć jako wrapper na
encję
udostępnia zestaw metod biznesowych
pozwalających operować na konkretnym modelu,
który reprezentuje (i tylko na nim)
194. Pomysł - obiekt biznesowy
●
Niech encja reprezentuje tylko i wyłącznie
schemat relacyjny w świecie obiektowym
●
Encje jedynie jako reprezentacje tabel
●
Encja anemiczna
●
Obiekt biznesowy – reprezentant modelu
na początku można o nim myśleć jako wrapper na
encję
udostępnia zestaw metod biznesowych
pozwalających operować na konkretnym modelu,
który reprezentuje (i tylko na nim)
nie istnieje "niezapisany"
195. @Configurable
public abstract class BusinessObject<T extends
Identifiable<K>, K> implements Serializable {
protected T entity;
private Class<T> clazz;
@PersistenceContext private EntityManager entityManager;
public BusinessObject(T entity, Class<T> clazz) {
this.entity = checkNotNull(entity);
this.clazz = clazz;
}
public T attached() {
return entityManager().find(clazz, entity.getId());
}
public K getId() { return attached().getId(); }
public boolean equals(Object o) { .. }
public int hashCode() {..}
197. @Configurable
public class User
extends BusinessObject<UserEntity, Long> {
public User(UserEntity entity) {
super(entity, UserEntity.class);
}
public void addRole(Role role) {
attached().addRole(role.attached());
attached().setLastModificationDate(new DateTime());
}
}
198. @Service
public class UserCreator {
@PersistenceContext
private EntityManager entityManager;
@Transactional
public User create(final String login) {
UserEntity entity = new UserEntity();
entity.setLogin(login);
entity.setCreationDate(new DateTime());
entityManager.persist(entity);
return new User(entity);
}
}
199. @Configurable
public class Group
extends BusinessObject<GroupEntity, Long> {
public Group(GroupEntity entity) {.. }
public Subgroup addSubgroup(String name) {
SubgroupEntity se = new SubgroupEntity();
se.setName(name);
attached().addSubgroup(se);
entityManager.persist(se);
return new Subgroup(se);
}
}
200. @Service
public class UserFinder {
@PersistenceContext
private EntityManager entityManager;
@Transactional(readOnly = true)
public User find(Long id) {
UserEntity entity =
entityManager.find(UserEntity.class, id);
return entity == null ? null : new User(entity);
}
}
201. @Service
public class DefaultUCUpdatingPoiCoordinates
implements UCUpdatingPoiCoordinates {
@Autowired PoiFinder poiFinder;
@Autowired MailSender mailSender;
public ActionPossible canUpdate() {..}
ActionPossible canUpdateWithArgs(Long poiId,
Coordinates c) {..}
public void update(Long poiId, Coordinates c) {
checkThat(canUpdate());
checkArguments(canUpdateWithArgs(poiId,c));
poiFinder.find(poiId).updateCoordinates(c);
mailSender.send(createContent());
}
204. public class Contest
extends BusinessObject<ContestEntity, Long> {
public boolean isLaunchable() {..}
public void launch() {..}
public boolean isFinishable() {..}
public void finish() {..}
...
}
205. public class Contest
extends BusinessObject<ContestEntity, Long> {
public ContestLifecycle lifecycle() {
return new ContestLifecycle(attached());
}
}
public class ContestLifecycle
extends BusinessObject<ContestEntity, Long> {
public boolean isLaunchable() {..}
public void launch() {..}
public boolean isFinishable() {..}
public void finish() {..}
}
206. public class NewContest
extends BusinessObject<ContestEntity, Long> {
public RunningContest launch() {..}
}
public class RunningContest
extends BusinessObject<ContestEntity, Long> {
public ClosedContest finish() {..}
}
public class ClosedContest
extends BusinessObject<ContestEntity, Long> {
}