Overview Structureshy Object pattern Better separation of concerns
Overview • Structure-shy Object pattern • Better separation of concerns using Structure-shy Traversal and Selective Visitor • Cover now more details 9/25/2020 SD 1
Structure-shy object pattern • Parsing, class graphs etc. • separation of concerns: – sentences : robust representation – objects : brittle representations – grammars: rules for constructing brittle rep. from robust rep. • XML, JSR 31 9/25/2020 SD 2
Parsing • • • class graphs class dictionaries = class graphs + syntax legal objects printing function defines language defined by class dictionary ambiguous class dictionary: two distinct objects are mapped to same sentence 9/25/2020 SD 3
Class graphs • • • construction, alternation nodes and edges textual and graphical common parts, flat class graphs optional parts and repetition parameterized classes 9/25/2020 SD 4
Exercise • Derive a class graph for explaining concrete class structure and syntax. 9/25/2020 SD 5
Parsing • Is a class dictionary ambiguous? • If not ambiguous, can define inverse of printing function: called parsing • Goal: Want a fast parser. Want to quickly recognize an unambiguous class dictionary. 9/25/2020 SD 6
Parsing • Inherent problem: There is no algorithm to check for ambiguity. Shown by reduction: Could solve other undecidable problems. • Invent condition which is stronger than nonambiguity and which can be checked efficiently. Ok. to exclude some nonambiguous grammars. • LL(1) conditions. 9/25/2020 SD 7
Parsing • LL(1) condition 1: Alternatives of abstract class must have pair-wise disjoint first sets. • LL(1) condition 2: Deals with alternatives which may be empty. Requires follow sets. • LL(1) conditions can be checked efficiently. • Printing is a bijection between tree objects and sentences. 9/25/2020 SD 8
Commercial parsing tools • Yacc and Lex • Java. CC (Java compiler) LL(k) support • JJTree: define classes using a grammar and provides a universal visitor • many more 9/25/2020 SD 9
Context switch: Separation of concerns • An introduction to aspect-oriented programming 9/25/2020 SD 10
Better separation of concerns • An old topic: Dijkstra 1976 • Minimize tangling 9/25/2020 SD 11
Two types of concerns • Generic concerns – – – – 9/25/2020 • Behaviors – – – structure coordination remote invocation exception handling efficiency interoperability migration SD sum check print translate Pricing Frequent. Customer. Pricing 12
interface Shape. I extends Remote { double void void public class Shape implements Shape. I { protected Adjustable. Location loc; protected Adjustable. Dimension dim; public Shape() { loc = new Adjustable. Location(0, 0); dim = new Adjustable. Dimension(0, 0); } double get_x() throws Remote. Exception { return loc. x(); } void set_x(int x) throws Remote. Exception { loc. set_x(); } double get_y() throws Remote. Exception { return loc. y(); } void set_y(int y) throws Remote. Exception { loc. set_y(); } double get_width() throws Remote. Exception { return dim. width(); } void set_width(int w) throws Remote. Exception { dim. set_w(); } double get_height() throws Remote. Exception { return dim. height(); } void set_height(int h) throws Remote. Exception { dim. set_h(); } void adjust. Location() throws Remote. Exception { loc. adjust(); } void adjust. Dimensions() throws Remote. Exception { dim. adjust(); } } 9/25/2020 get_x() throws Remote. Exception ; set_x(int x) throws Remote. Exception ; get_y() throws Remote. Exception ; set_y(int y) throws Remote. Exception ; get_width() throws Remote. Exception ; set_width(int w) throws Remote. Exception ; get_height() throws Remote. Exception ; set_height(int h) throws Remote. Exception ; adjust. Location() throws Remote. Exception ; adjust. Dimensions() throws Remote. Exception ; } class Adjustable. Location { protected double x_, y_; public Adjustable. Location(double x, double y) { x_ = x; y_ = y; } synchronized double get_x() { return x_; } synchronized void set_x(int x) {x_ = x; } synchronized double get_y() { return y_; } synchronized void set_y(int y) {y_ = y; } synchronized void adjust() { x_ = long. Calculation 1(); y_ = long. Calculation 2(); } } class Adjustable. Dimension { SD } protected double width_=0. 0, height_=0. 0; public Adjustable. Dimension(double h, double w) { height_ = h; width_ = w; } synchronized double get_width() { return width_; } synchronized void set_w(int w) {width_ = w; } synchronized double get_height() { return height_; } synchronized void set_h(int h) {height_ = h; } synchronized void adjust() { width_ = long. Calculation 3(); height_ = long. Calculation 4(); 13 }
thread synchronization remote interaction interface Shape. I extends Remote { double void void public class Shape implements Shape. I { protected Adjustable. Location loc; protected Adjustable. Dimension dim; public Shape() { loc = new Adjustable. Location(0, 0); dim = new Adjustable. Dimension(0, 0); } double get_x() throws Remote. Exception { return loc. x(); } void set_x(int x) throws Remote. Exception { loc. set_x(); } double get_y() throws Remote. Exception { return loc. y(); } void set_y(int y) throws Remote. Exception { loc. set_y(); } double get_width() throws Remote. Exception { return dim. width(); } void set_width(int w) throws Remote. Exception { dim. set_w(); } double get_height() throws Remote. Exception { return dim. height(); } void set_height(int h) throws Remote. Exception { dim. set_h(); } void adjust. Location() throws Remote. Exception { loc. adjust(); } void adjust. Dimensions() throws Remote. Exception { dim. adjust(); } } 9/25/2020 get_x() throws Remote. Exception ; set_x(int x) throws Remote. Exception ; get_y() throws Remote. Exception ; set_y(int y) throws Remote. Exception ; get_width() throws Remote. Exception ; set_width(int w) throws Remote. Exception ; get_height() throws Remote. Exception ; set_height(int h) throws Remote. Exception ; adjust. Location() throws Remote. Exception ; adjust. Dimensions() throws Remote. Exception ; } class Adjustable. Location { protected double x_, y_; public Adjustable. Location(double x, double y) { x_ = x; y_ = y; } synchronized double get_x() { return x_; } synchronized void set_x(int x) {x_ = x; } synchronized double get_y() { return y_; } synchronized void set_y(int y) {y_ = y; } synchronized void adjust() { x_ = long. Calculation 1(); y_ = long. Calculation 2(); } } class Adjustable. Dimension { SD } protected double width_=0. 0, height_=0. 0; public Adjustable. Dimension(double h, double w) { height_ = h; width_ = w; } synchronized double get_width() { return width_; } synchronized void set_w(int w) {width_ = w; } synchronized double get_height() { return height_; } synchronized void set_h(int h) {height_ = h; } synchronized void adjust() { width_ = long. Calculation 3(); height_ = long. Calculation 4(); 14 }
The source of tangling Alignment with classes would be nice, but. . . 9/25/2020 SD 15
The source of tangling . . . issues cross-cut classes 9/25/2020 SD 16
interface Shape. I extends Remote { double get_x() throws Remote. Exception ; void set_x(int x) throws Remote. Exception ; double get_y() throws Remote. Exception ; void set_y(int y) throws Remote. Exception ; double get_width() throws Remote. Exception ; void set_width(int w) throws Remote. Exception ; double get_height() throws Remote. Exception ; void set_height(int h) throws Remote. Exception ; void adjust. Location() throws Remote. Exception ; void adjust. Dimensions() throws Remote. Exception ; } public class Shape implements Shape. I { protected Adjustable. Location loc; protected Adjustable. Dimension dim; public Shape() { loc = new Adjustable. Location(0, 0); dim = new Adjustable. Dimension(0, 0); } double get_x() throws Remote. Exception { return loc. x(); } void set_x(int x) throws Remote. Exception { loc. set_x(); } double get_y() throws Remote. Exception { return loc. y(); } void set_y(int y) throws Remote. Exception { loc. set_y(); } double get_width() throws Remote. Exception { return dim. width(); } void set_width(int w) throws Remote. Exception { dim. set_w(); } double get_height() throws Remote. Exception { return dim. height(); } void set_height(int h) throws Remote. Exception { dim. set_h(); } void adjust. Location() throws Remote. Exception { loc. adjust(); } void adjust. Dimensions() throws Remote. Exception { dim. adjust(); } } class Adjustable. Location { protected double x_, y_; public Adjustable. Location(double x, double y) { x_ = x; y_ = y; } synchronized double get_x() { return x_; } synchronized void set_x(int x) {x_ = x; } synchronized double get_y() { return y_; } synchronized void set_y(int y) {y_ = y; } synchronized void adjust() { x_ = long. Calculation 1(); y_ = long. Calculation 2(); } } class Adjustable. Dimension { protected double width_=0. 0, height_=0. 0; public Adjustable. Dimension(double h, double w) { height_ = h; width_ = w; } synchronized double get_width() { return width_; } synchronized void set_w(int w) {width_ = w; } synchronized double get_height() { return height_; } synchronized void set_h(int h) {height_ = h; } synchronized void adjust() { width_ = long. Calculation 3(); height_ = long. Calculation 4(); } } 9/25/2020 D public class Shape { protected double x_= 0. 0, y_= 0. 0; protected double width_=0. 0, height_=0. 0; Write this Instead of writing this SD double get_x() { return x_(); } void set_x(int x) { x_ = x; } double get_y() { return y_(); } void set_y(int y) { y_ = y; } double get_width(){ return width_(); } void set_width(int w) { width_ = w; } double get_height(){ return height_(); } void set_height(int h) { height_ = h; } void adjust. Location() { x_ = long. Calculation 1(); y_ = long. Calculation 2(); } void adjust. Dimensions() { width_ = long. Calculation 3(); height_ = long. Calculation 4(); } } coordinator Shape { selfex adjust. Location, adjust. Dimensions; mutex {adjust. Location, get_x, set_x, get_y, set_y}; mutex {adjust. Dimensions, get_width, get_height, set_width, set_height}; } portal Shape { double get_x() {} ; void set_x(int x) {}; double get_y() {}; void set_y(int y) {}; double get_width() {}; void set_width(int w) {}; double get_height() {}; void set_height(int h) {}; void adjust. Location() {}; void adjust. Dimensions() {}; } 17
Code tangling is bad • Harms program structure • Distracts from main functionality • Hard to program, error-prone • Code difficult to understand, maintain 9/25/2020 SD 18
Ways to decrease the tangling • Style guidelines • Design patterns • Better programming languages 9/25/2020 SD 19
Tangling of traversal/visitor calls class graph traversal + visitor calls A = B. B = C. C = D. D=. class A void t(V v){ v. before_b(this); b. t(v); v. after_b(this); } class B void t(V v){ v. before_c(this); c. t(v); v. after_c(this); } 9/25/2020 SD visitor class V before_b(A host) { …} after_b(A host) { …}. . . 20
Tangling of behaviors V and W class graph A = B. B = C. C = D. D=. visitor class V visitor class W traversal + visitor calls class A: void f() {t(new V(), new W()); } void t(V v, W w){ v. before_b(this); w. before_b(this); b. t(v, w); w. after_b(this); v. after_b(this); } class B: void t(V v, W w){ v. before_c(this); w. before_c(this); c. t(v, w); w. after_c(this); v. after_c(this); } At design level: class A: void f() to D (V, W) 9/25/2020 SD 21
AOP => control of tangling • Demeter. J controls the following tangling problems – – – 9/25/2020 structure/behavior, navigation/behavior, behavior/behavior, object construction/structure, synchronization/behavior, remote invocation/behavior. SD 22
Context switch 9/25/2020 SD 23
Developing an adaptive program • each simple behavior is translated into a visitor; localizes concerns; visitors are selfcontained • compose visitors, order visitors • use top-down approach for writing program: first write method using visitors before visitors are implemented 9/25/2020 SD 24
Container capacity problem • • • recursive containers each contains items and has capacity each item has a weight find all containers above capacity leave details of containers vague 9/25/2020 SD 25
Container capacity problem • need to sum: use Summing. Visitor • need to check: use Checking. Visitor • want to do it in one traversal: need to store sum when container is entered to compute difference after the container: Difference. Visitor 9/25/2020 SD 26
Summing before Weight Traversal Difference Checking before Container after Container Summary of code Summary of data flow s d v Summary of event flow before Weight before Container after Container Event based view of traversals and visitors 9/25/2020 SD 27
Summing before Weight Summary of code return s Traversal Summary of data flow Difference Checking before Container after Container return d return v s d v Summary of event flow before Weight before Container after Container Event based view of traversals and visitors 9/25/2020 SD 28
Visitor classes as components return visitor class strategy s class graph Difference Summing return total diff sum what? get_value 9/25/2020 Checking check what? get_capacity SD 29
Which Conceptual View? Most basic innermost Checking uses Difference uses Summing Checking. Visitor after Container Traversal Difference. Visitor before Container after Container node and edge events 9/25/2020 Summing. Visitor before Weight SD 30
Which Conceptual View? Most basic outermost: filter Checking uses Difference uses Summing Traversal Summing. Visitor before Weight Difference. Visitor before Container after Container node and edge events Checking. Visitor after Container 9/25/2020 SD 31
Traversals are iterative • from Container to Weight: total = total + host. get_i(); • some recursive computations need extra attention using difference visitors 9/25/2020 SD 32
Container capacity problem • Summing. Visitor – data member total, initialize to 0 – add at Weight 9/25/2020 SD 33
Container capacity problem • Checking. Visitor – data member: violations – after each container, check whether difference of sum at the end and the beginning of a container (supplied by Difference. Visitor) is larger than capacity – uses Difference. Visitor – return violations 9/25/2020 SD 34
Container capacity problem • Difference. Visitor – store sum at beginning (Summing. Visitor) of container – return difference between sum at beginning of container and current sum upon request – uses Summing. Visitor twice per container 9/25/2020 SD 35
Container capacity problem • Preliminary visitor class graph! Checking. Visitor = <d. V> Difference. Visitor = <s. V> Summing. Visitor. • Visitor order: after container, both Difference. Visitor and Checking. Visitor are active. • Difference. Visitor must be after Checking. Visitor (because after methods are in reverse order) 9/25/2020 SD 36
Demeter. J Container capacity problem traversal all. Weights(Checking. Visitor c. V, Difference. Visitor d. V, Summing. Visitor s. V) {to Weight; } int check. Capacity() {{ Checking. Visitor c. V = new Checking. Visitor(); Difference. Visitor d. V = new Difference. Visitor(); Summing. Visitor s. V = new Summing. Visitor(); c. V. set_d. V(d. V); d. V. set_s. V(s. V); //link behaviors this. all. Weights(c. V, d. V, s. V); // call traversal with visitors return (c. V. get_return_val()); }} cannot avoid all tangling, but can localize it. No longer spread over several classes. 9/25/2020 SD 37
DJ Container capacity problem int check. Capacity(Traversal. Graph where. To. Go) { Checking. Visitor c. V = new Checking. Visitor(); Difference. Visitor d. V = new Difference. Visitor(); Summing. Visitor s. V = new Summing. Visitor(); c. V. set_d. V(d. V); d. V. set_s. V(s. V); //link behaviors Integer res = (Integer) where. To. Go. traverse(this, new Visitor[]{c. V, d. V, s. V}); return res. int. Value(); } cannot avoid all tangling, but can localize it. No longer spread over several classes. 9/25/2020 SD 38
Container capacity problem • Refined visitor class graph Checking. Visitor = <d. V> Difference. Visitor <violations> int. Difference. Visitor = <s. V> Summing. Visitor <difference> int <stack> Stack. // from java. util. *; Summing. Visitor = <total> int. 9/25/2020 SD 39
Demeter. J Checking. Visitor init {{ violations = 0; }} after Container {{ diff = // use d. V cap = host. get_capacity() if (diff > cap) violations = violations + 1; }} return int {{ violations }} need to give return type since Demeter. J does not analyze code between {{ and }} 9/25/2020 SD 40
DJ Checking. Visitor void start() {violations = 0; } void after(Container host) { diff = // use d. V cap = host. get_capacity() if (diff > cap) violations = violations + 1; } Object get. Return. Value() {return new Integer(violations); } 9/25/2020 SD 41
Demeter. J Difference. Visitor init {{ stack = new Stack(); }} before Container {{ stack. push(… s. V. get_total() …); }} after Container {{ difference = s. V. get_return_val() - … (Integer) stack. pop() …; }} return int {{ difference }} 9/25/2020 SD 42
DJ Difference. Visitor void start() { stack = new Stack(); } void before(Container host){ stack. push( s. V. get. Return. Value()); } void after(Container host) { diff = ((Integer) s. V. get. Return. Value()). int. Value() ((Integer) stack. pop()). int. Value(); } Object get. Return. Value() {return new Integer(diff); } 9/25/2020 SD 43
Demeter. J Summing. Visitor init {{ total = 0; }} before Weight {{ total = total + host. get_i(); }} return int {{ total }} 9/25/2020 SD 44
DJ Summing. Visitor { {{ void start() { total = 0; } void before(Weight host) { total = total + host. get_i(); } Object get. Return. Value() {return new Integer(total); } }} } 9/25/2020 SD 45
Adaptiveness • program we developed can be used with many different class graphs which satisfy a small set of constraints: – Container must contain Weight – Weight must have data member i of type int – Container must have data member capacity • 2 examples 9/25/2020 SD 46
Class graphs Container = <contents> List(Item) <capacity> Capacity. Item : Container | Simple. List(S) ~ {S}. Simple = <name> Ident <w> Weight. Capacity = <i> int. Weight = <i> int. alternative: move <w> Weight to Item 9/25/2020 SD 47
Class graphs Container : Container 1 | Container 2 common <contents> List(Item) <capacity> Capacity. Container 1 = <packaging 1> Simple. Container 2 = <packaging 2> Simple. Item : Container | Simple common <w> Weight. List(S) ~ {S}. Simple = <name> Ident. Capacity = <i> int. Weight = <i> int. 9/25/2020 SD 48
- Slides: 48