/* --- CSU213 Spring 2006 Lecture Notes --------- Copyright 2006 Viera K. Proulx Lecture 3: All in the Family */ /* Goals: - recall data definitions for self-referential data from HtDP - translate data definitions into class diagrams and Java code - understand that the concepts are the same Recall the problem dealing with ancerstor trees in HtDP. The data definition was: ;; An Ancestor Tree (AT) is one of ;; -- "not known" ;; -- (make-at String AT AT) (define-struct at (name mother father)) Let us think of some examples. Adam's mother is Celeste, his father is George. Celeste's mother is Anne, her father is Jack. George's mother is Eugenia and his father is Oswald. We know that Eugenia's mother was Amalie, but that is all we know about the ancestors of Adam. We can represent the ancestor tree of Adam's linage as follows: nk nk | | -------- | nk nk nk nk Amalie nk nk nk | | | | | | | | ------- ------ --------- -------- | | | | Anne Jack Eugenia Oswald | | | | ---------- -------------- | | Celeste George | | ---------------------- | Adam We know how to represent this information as Scheme data: (define adam-at (make-at "Adam" (make-at "Celeste" (make-at "Anne" "not known" "not known") (make-at "Jack" "not known" "not known")) (make-at "Celeste" (make-at "Eugenia" (make-at "Amalie" "not known" "not known") "not known") (make-at "Oswald" "not known" "not known")))) Let us think how this data definition would look when expressed as a class diagram. It is clear that AT represents a union of two classes, so we need an interface AT to represent the common name for the two classes. Furthermore, the class that represents the unknown part of the ancestor tree has to be a class on its own, but no additional information has to be recorded, and so, it will have no fields. Finally, the class that represents a person in the tree needs to record the name of this person, and know about the ancestor tree of her mother and her father. This suggests that we use containment. The final diagram becomes: +--------------------+ | +---------------+ | | | | | v v | | +--------------+ | | | interface AT | | | +--------------+ | | /|\ | | | | | - - - - - - - - - | | | | | | +------+ +-------------+ | | | NKAT | | PersonAT | | | +------+ +-------------+ | | +------+ | String name | | | | AT mother |--+ | | AT father |----+ +-------------+ We are now ready to define Java classes - we need the classes NKAT and PersonAT, both of them implementing the common interface AT. Furthermore, the class PersonAT has three fields, name, mother, and father, with the last two of the type AT. Here are the class definitions together with our earlier examples translated into Java code: */ // to represent an ancestor tree interface AT { } // to represent unknown branch of an ancestor tree class NKAT implements AT { NKAT() { } } // to represent a person's ancestry class PersonAT implements AT { String name; AT mother; AT father; PersonAT(String name, AT mother, AT father) { this.name = name; this.mother = mother; this.father = father; } } class Examples { Examples () {} // an example of the unknown branch of an ancestor tree AT nk = new NKAT(); // examples of person's ancsatries AT amalie = new PersonAT("Amalie", this.nk, this.nk); AT anne = new PersonAT("Anne", this.nk, this.nk); AT jack = new PersonAT("Jack", this.nk, this.nk); AT eugenia = new PersonAT("Eugenia", this.amalie, this.nk); AT oswald = new PersonAT("Oswald", this.nk, this.nk); AT celeste = new PersonAT("Celeste", this.anne, this.jack); AT george = new PersonAT("George", this.eugenia, this.oswald); AT adam = new PersonAT("Adam", this.celeste, this.george); }