Software Construction: Object-Oriented Design Flashcards
A call-stack is formed when
one method calls another.
Exception mechanisms in a programming language let us
write code to recover from errors, and resume normal execution of the code.
Throwing the exception object causes
an alternate return path to be taken: once an exception is thrown, none of the subsequent code in that method is executed. Instead, the exception object can be thought of as falling back down the return path to the calling method
Normal execution through the normal return path does not
resume until the exception is caught. If the exception is not caught it keeps falling down the alternate exceptional path until the program effectively crashes.
A method should only catch an exception if it can actually
do the work to recover from (handle) that exception.
unchecked exceptions and checked exceptions
unchecked doesnt check by java, checked - checked
To Extract a class hierarchy
we look at all the “extends” and “implements” relationships between classes and interfaces in our system.
To Extract associations
we look at the fields within the classes.
If a class contains a field of another type, then... We would draw the association on the diagram, and indicate...
...we say that the class is associated with that other type. ...what the arity of the association i
An Aggregation relationship can be thought of as
a whole-part relationship. If one object is part of another object, then we use a diamond at the start of the arrow (next to the containing object), and a normal arrow at the end.
A sequence diagram depicts
the calls between objects while the system is running. It’s essentially a vertical timeline of calls, that flows from top to bottom.
A sequence diagram starts
with a particular method call – so effectively, we are drawing the sequence of calls triggered by one method.
At the top of the diagram,
all the objects that are “alive” through the execution of the method are depicted. They then have lifelines (timelines) extending down from them.
To show a method’s execution on the timeline, we draw
a box that overlays the timeline. The box extends for as long as that method runs.
Calls to a method are depicted as
arrows with the name of the method sitting as the label. Parameters are listed in parentheses. The destination object for a call is the object in which that method is implemented. The call arrow extends from the calling object’s method to the called method.
Loops are shown in sequence diagram by
placing a box around all the looped behaviour, and putting the condition of the loop in the corner.
Conditional behaviour in sequence diagram is shown as
a box around all the conditional behaviour, with the condition indicated in the corner.
To Implement Fields we look at
associations between classes.
The type of the field is determined by
the destination type of the association arrow.
There are three kinds of Bi-Directional Relationships
one-one relationships, one-many relationships, and many-many relationships.
When Implementing Sequence Diagrams begin by looking at
the method coming in from the side – this tells us the name of the method being implemented.
SOLID
Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation and Dependency Inversion. Of those we will look at Single Responsibility and Liskov Substitution
The Single Responsibility Principle indicates that
each class should be centered around one cohesive concept
If, over time, a class seems like it has more than one responsibility, it can be
split into two separate classes
A symptom of having two responsibilities is
having multiple clusters of methods, with each cluster referring to their own data within the class. Each cluster may represent its own responsibility, and may be best separated into its own class.
Coupling between two classes indicates that
two classes collaborate in some way.
Inter-class coupling can be through
method calls, dependencies, or by holding functionality in common that accomplishes a goal without explicitly declaring as such.
Low coupling
a change in one place requires no change in a collaborating class
Medium coupling
a change in one class does require a remote change, but the compiler warns the developer that the change is needed. An example of this is when a checked exception is declared to be thrown, the compiler will alert the developer that it must be caught at the calling location. Method signature changes are also checked by the compiler, as are Type changes.
High coupling
a change in one class does require a remote change, but the collaboration will only be detected at runtime – meaning you have to run the code to see that the change has affected other classes.
One way to refactor semantic coupling is to
introduce a new type of object to reduce duplication.
The Liskov Substitution Principle states that
for a subclass to be substitutable for its superclass, the subclass cannot break the expectations that a user of the superclass would have. Thus, it cannot reduce the service it provides, and cannot produce effects not produced in the superclass.
It formally states that
the preconditions of a subclass’s behaviour (methods) cannot be strengthened, meaning (among other things) that a sub-method cannot accept a narrower range of inputs than the original method.
The post conditions of a sub-method cannot be weakened, meaning that the sub-method cannot have a broader range of effect than the original method.
Тип тестов для LSP
- substitution test Student s = new StudentRegSys(); Bird b = new Eagle(); - concatenation test StudentRegSys Student Eagle Bird -IS-A test StudentRegSys IS-A Student Eagle IS-A Bird
The Composite Pattern provides
a design for a hierarchy, in which nodes with children differ in their behaviour from nodes with no children. An example might be the display of a hierarchy, like a file system, where folders contain files. Folders would be displayed differently from files, and would have contents (the files).
The composite pattern consists of
three classes: the Composite (the node that can have children), the Leaf (no children), and the Component, which is a superclass extended by both the Composite and Leaf
The Composite has a collection
of Components, so that the Composite class can loop through those Components without keeping track of whether the Component is actually a Composite or a Leaf.
The Composite also has an method
addComponent method so that Components can be added to its contents.
Without the Component super class abstraction,
the Composite would have to maintain different lists for each kind of element in its contents, and would need to provide individual methods for adding contents, and displaying contents for each kind of content.
The Observer Pattern is a design that lets
one or more objects watch the state of one or more other objects.
The Observer Pattern design centers around two phases
Registration: The Observer registers with the Subject, by calling a registration method on the subject (named something like register, or addObservers). In that method, the Subject adds the Observer to its list of Observers.
Notification: Whenever the Subject’s state changes, it notifies the observers by calling its own notify (or similarly named) method. The notify method then iterates through the list of observers, calling update (or a similarly named method) on each one. The Subject may send an argument with this method to indicate the change (the push model), or may send a reference to itself so that the Observer can call back to find out what changed for itself (the pull model).
The Iterator Pattern allows us to
separate out all the logic for iterating over a collection.