Title: Synthetic OOD concepts and reuse Lecture 3: Separation of concerns
1Synthetic OOD concepts and reuse Lecture 3
Separation of concerns
- Topics
- Separation of concerns as a general principle for
managing complexity in software designs - Example problems
- Managing dependencies in complex configurations
- Need to isolate operations over composite
structures - Visitor pattern Systematic design technique for
encapsulating operations over such structures
into a single class
2Softw. design body of knowledge
- Organized around a set of core principles
- Separation of concerns
- Abstraction
- Anticipation of change
- Modularity
- Generality
- Incrementality
- Goal At end of this course, you should be able
to apply these principles with proficiency in
real design contexts.
Source Fundamentals of Software Engineering
by Ghezzi, Jazayeri, and Mandrioli
3Quote from Edsgar Dijkstra
- Let me try to explain what is characteristic for
all intelligent thinking. It is, that one is
willing to study in depth an aspect of one's
subject matter in isolation for the sake of its
own consistency, all the time knowing that one is
occupying oneself only with one of the aspects.
We know that a program must be correct and we can
study it from that viewpoint only we also know
that it should be efficient and we can study its
efficiency on another day, so to speak. In
another mood we may ask ourselves whether, and if
so why, the program is desirable. But nothing is
gained --on the contrary!-- by tackling these
various aspects simultaneously. It is what I
sometimes have called "the separation of
concerns", which, even if not perfectly possible,
is yet the only available technique for effective
ordering of one's thoughts, that I know of. This
is what I mean by "focussing one's attention upon
some aspect" it does not mean ignoring the other
aspects, it is just doing justice to the fact
that from this aspect's point of view, the other
is irrelevant. It is being one- and
multiple-track minded simultaneously.
4Separation of concerns (SoC)
- Very general principle of software engineering,
indeed any intellectual activity - Suggests that we should manage complexity by
separating (or avoid unnecessarily mixing)
conceptually unrelated aspects of a problem or
solution - A clean separation allows each concern to be
dealt with in isolation and for the composition
of concerns to be well understood - OO Design is flush with patterns and idioms for
separating concerns - Lets look at a few of them
5Opportunities for SoC in OO Design
- Issue Need to minimize time required to rebuild
a large software system that is being updated - Concern Management of rebuild dependencies among
files - Problem Program understanding when code contains
interleaved strands that accomplish distinct
purposes - Code that implements these distinct purposes
tends to be tangled together - Code for a single purpose may be scattered across
many classes and functions - Concerns Each distinct purpose or feature
- Idea Manage complexity by disentangling these
functionally distinct code strands
6Opportunities for SoC in OO Design
- Issue Need to minimize time required to rebuild
a large software system that is being updated - Concern Management of rebuild dependencies among
files - Problem Program understanding when code contains
interleaved strands that accomplish distinct
purposes - Code that implements these distinct purposes
tends to be tangled together - Code for a single purpose may be scattered across
many classes and functions - Concerns Each distinct purpose or feature
- Idea Manage complexity by disentangling these
functionally distinct code strands
7Problem Recompiling large systems
- Large software may require hours rather than
minutes to rebuild from scratch - Solution well known
- Cleanly separate class declarations from class
definitions - Place each declaration or definition in separate
file - Create a Makefile that documents the
recompilation dependencies and the commands to
rebuild - Concern Dependency/configuration management
- Must not miss any dependencies!
- Becomes difficult when header files include
other header files
8Example
- A.o A.cc
- g -c A.cc
- B.o B.cc
- g -c B.cc
- C.o C.cc
- g -c C.cc
- main.o main.cc
- g -c main.cc
- app main.o A.o B.o C.o
- g -o _at_ main.o A.o B.o C.o
- B.o A.h B.h
- C.o A.h B.h C.h
- main.o A.h B.h C.h
- System with three classes, A, B, and C, and a
main - A.cc includes A.h
- B.cc includes B.h
- C.cc includes C.h
- B.h includes A.h
- C.h includes B.h
- main.cc includes C.h
What if you forget these?
9SoC to the rescue
- Dependency management is a real concern that
could benefit from separation - Solution Use a tool to generate those nested
header dependencies for you - E.g., makedepend(1)
- Requires you to
- instrument Makefile so that dependencies can be
added - re-run makedepend whenever you make a change that
might affect recompilation dependencies
10Example (modified Makefile)
- .SUFFIXES .cc .o
- .cc.o
- g -c lt
- SRCSA.cc B.cc C.cc main.cc
- OBJSSRCS.cc.o
- app OBJS
- g -o _at_ OBJS
- depend
- makedepend SRCS
Notice depend target runs makedepend to
regenerate header dependencies, which are
appended to end of Makefile
11Example Minimize dependencies
- include B.h
- class A
- public
- ...
- protected
- const B bVar
- class B
- class A
- public
- ...
- protected
- const B bVar
Notice Forward declaration of class B expresses
As dependency on B without including the entire
declaration of B
12Opportunities for SoC in OO Design
- Issue Need to minimize time required to rebuild
a large software system that is being updated - Concern Management of rebuild dependencies among
files - Problem Program understanding when code contains
interleaved strands that accomplish distinct
purposes - Code that implements these distinct purposes
tends to be tangled together - Code for a single purpose may be scattered across
many classes and functions - Concerns Each distinct purpose or feature
- Idea Manage complexity by disentangling these
functionally distinct code strands
13Motivation
- Suppose we have a class hierarchy that
instantiates the composite pattern - E.g., expression-tree hierarchy
- Lots of polymorphic operations that we might want
to implement - E.g., type checking
- E.g., pretty printing
- E.g., evaluation
14Question
- Suppose we have an existing Expr hierarchy that
supports type checking and evaluation, but not
pretty printing. How many classes must we modify
in order to add pretty printing?
15Visitor pattern
- Allows addition of new polymorphic operations to
a class hierarchy without modifying any of the
classes - Requires two hierarchies
- Original composite hierarchy
- Visitor-class hierarchy
- New operations implemented by specializing
visitor class hierarchy
16More precisely
- Visitor-class hierarchy must have a most abstract
root class - Every class in the subject hierarchy provides a
polymorphic accept operation, which - takes a reference to the visitor-hierarchy root
class as a parameter - invokes a subject-class specific method on this
parameter, passing itself (i.e., the object that
received the accept message) as a parameter - E.g., the body of accept method in class X would
invoke method visitX on visitor object, passing
this as a parameter
17Example Expression Visitor
- class ExprVisitor
- public
- virtual void visitLiteralExpr(LiteralExpr)
- virtual void visitAddExpr(AddExpr)
- virtual void visitVarExpr(VarExpr)
- virtual void visitSubtractExpr(SubtractExpr)
18Accept operation
- class Expr
- public
- virtual Expr()
- virtual void accept(ExprVisitor)0
- protected
- Expr()
-
- class LiteralExpr public Expr
- public
-
- virtual void accept( ExprVisitor v )
- v.visitLiteralExpr(this)
-
19Accept operation (continued)
- class AddExpr public Expr
- public
- void accept( ExprVisitor v )
- protected
- Expr left
- Expr right
-
- void AddExpraccept( ExprVisitor v )
- left-gtaccept(v)
- right-gtaccept(v)
- v.visitAddExpr(this)
20Example Evaluation visitor
- class EvaluateVisitor public ExprVisitor
- public
- double getValue()
- void visitLiteralExpr( LiteralExpr )
- void visitVarExpr( VarExpr )
- void visitAddExpr( AddExpr )
- void visitSubtractExpr( SubtractExpr )
- protected
- stackltdoublegt valStack
21Evaluation visitor (continued)
- void EvaluateVisitorvisitLiteral( LiteralExpr
l ) - valStack.push(l-gtvalue())
- void EvaluateVisitorvisitAdd( AddExpr a )
-
- double rightVal(valStack.top())
- valStack.pop()
- double leftVal(valStack.top())
- valStack.pop()
- valStack.push( leftVal rightVal )
-
22Exercise
- Suppose we have
- Expr e new AddExpr( new LiteralExpr(5),
- new LiteralExpr(4) )
- Draw a UML sequence diagram that depicts the
execution of - EvaluationVisitor ev
- e-gtaccept(ev)
23Exercise
- Develop a pretty-print visitor for the example
Expr hierarchy