330 likes | 470 Vues
(For parallel treatment, see Chapter 2 of the text). OOD Case Study. Elements of Class Design. Static class diagram UML: Unified Modeling Language Pseudocode for operations Can be vague when it comes to details Should be precise about control and function. Criteria for Good Class Design.
E N D
(For parallel treatment, see Chapter 2 of the text) OOD Case Study
Elements of Class Design • Static class diagram • UML: Unified Modeling Language • Pseudocode for operations • Can be vague when it comes to details • Should be precise about control and function
Criteria for Good Class Design Correctness: solves the problem Simplicity Cohesion: everything in a class directed at a single purpose Coupling/Information Hiding: classes should never depend upon knowing the internal implementations of other classes Error Handling: design should be robust.
Problem Statement: The 8-Puzzle The 8-puzzle is a device consisting of eight numbered and sliding tiles arranged in a 3x3 grid. An 8-puzzle problem is an initial state and a final state along with a list of legal actions that can be performed on states. final initial 1 2 3 2 8 3 8 4 1 6 4 7 6 5 7 5 right down left up 2 8 3 2 8 3 2 8 3 2 8 3 1 4 1 6 4 1 6 4 1 6 4 7 6 5 7 5 7 5 7 5
8-Puzzle Problem Statement (cont'd) • You are to write a program that simulates the solving of an 8-puzzle problem. • Your program must display an initial state of the 8-puzzle and then prompt the player for an action. After displaying the initial state, the program repeatedly prompts for actions, displaying the results of each action until the final state is achieved. • If an action is not possible, that is, it attempts to move a tile into an occupied space or off the edge of the board, the program must issue a diagnostic message and reprompt the player. When the final state is reached, the number of actions made is displayed. Illegal attempted moves are not counted.
Important Aspects of the Problem Statement It describes the problem and defines precisely what constitutes a solution It makes clear the "rules of the game" It uses diagrams and examples It does not attempt to describe how the problem is to be solved, only what the problem is It specifies the program behavior in sufficient detail
Identifying Potential Classes:Collect Problem Statement Nouns State 8-puzzle Device Board Grid Tile Space Action Action List Solver Problem Message Player
Analyzing Potential Classes State: holds all information about an 8-puzzle state including how to move tiles 8-puzzle, Device, Board, Grid: redundant Tile: unnecessary Space: part of a State Action: contains a function for moving a tile Action List: collection of Actions, one for each legal move Problem: creates the Action List. Contains initial State, final State, and Action List Solver: contains the Problem, knows how to prompt and check for solution Message: unnecessary Player: unnecessary
A Primitive Class Diagram Problem <Data> <Operations> State <Data> <Operations> Action <Data> <Operations> ActionList <Data> <Operations> Solver <Data> <Operations>
Characterizing Classes Q: How do you determine which class to start with? A: Identify classes that do not depend on others for their definition: The Solver object requires a Problem to solve The Problem object requires an Initial State, Final State, and ActionList The ActionList object requires Actions The Action object requires a State on which to perform itself This leaves the State class as a good one with which to begin.
Class Diagram with Dependencies Solver Problem depends on <data> <data> <operations> <operations> depends on ActionList State depends on <data> <data> <operations> <operations> depends on depends on Action <data> <operations>
Elements of a Complete Class Diagram All data specified with types All operations specified with return types, parameters, and parameter types All operations specified as public or private (data should never be public) Class dependencies indicated via annotated connectors and arrows
Example: Solver Class Solver -problem: Problem +Solver(p: Problem) +solve(): void -promptActionName(): String
Notes on the Solver Class A ``-'' prefix indicates the data or operation is private, a ``+'' prefix indicates public. The constructor for a class has the same name as the class. The Solver constructor requires a Problem object from which to get the initial and final States, and the Action List. The solve operation is public since it will be called from outside the class. The promptActionName operation is private because it is used only by solve.
Another Example: The Problem Class Problem -startState: State -finalState: State -actionList: ActionList +Problem(startTileNums: StringArray) +getStartState(): State +getFinalState(): State +getActionList(): ActionList -createActionList(): void
Notes on the Problem Class The Problem constructor receives an array of strings from which to build the start State. getStartState, getFinalState, and getActionList are data accessors used by the Solve class. createActionList is a private operation that builds the ActionList by using the tile motion operations from the State class
Relationship of the Solver and Problem Classes Problem Solver -startState: State -finalState: State -actionList: ActionList problem 1 1 <Solver operations> <Problem operations>
Class Associations The Solver and Problem classes are related by association, a relationship between instances of classes. The label ``problem'' is the role name; the role that the Problem class plays for the Solver class. When there is a role name, it can be left out of the box in the interests of simplicity. The numbers at either end of the line are multiplicities; in this case there is always one solver and one problem
Pseudocode for the solve() Operation void solve() current = get start state from problem final = get final state from problem alist = get action list from problem count = 0 while current is not final do display current action = get action from user if action is valid then new = apply action to current current = new increment count else issue message display current and count congratulate
Notes on the Pseudocode Nonexecutable Control structures used (while, if...then) Loop details not explicit Code blocks indicated through indentation (personal preference)
State Class Data: Representation of the 8-puzzle board Representation of the blank position Operations: Create a new state Display the current configuration of the puzzle Check if state is equal to another Move blank up, down, left or right . . .
New Class Diagram Solver Problem -actionList: ActionList Problem 1 1 <Problem operations> <Solver operations> 1 startState finalState 2 State <State data> <State operations>
Action Class Data: Name (up, down, left, right) Operation to perform the action--What, an operation as data?? Operations: Create a new action Execute the action operation . . .
Action Class Notes Operations for moving the tile are already in the State class--why a separate Action class? Because we want to abstract out as much of the generic design as possible for use with other problems Abstraction is facilitated by having an ActionList composed of Actions. To put an action on a list, it has to be regarded as data. In C++, we will do this using pointers to static methods.
ActionList Class Data: The actions The total number of actions Operations: Create a new action list Add an action to the action list Find an action by name . . .
New Class Diagram Solver 1 1 Problem problem 1 1 startState finalState actionList 2 1 State ActionList Action * 1
Comments on New Diagram The relationship between ActionList and Action is one of aggregation, indicated by a diamond at the end of the line. The multiplicity ``*'' means ``any number''.
The Art of OOD There is no one correct design for a given problem. You may wish to emphasize classes other than those chosen here. You should design your solutions in a way which is natural to you. However you should strive for SIMPLICITY. Also, you should design for REUSE (difficult).
Advantages of Design Simplicity Easier to understand Easier to implement Easier to debug Easier to maintain
Designing For Reuse The general State class was chosen rather than the more specific 8-puzzle The Action, ActionList, and Solver classes do not know anything about the 8-puzzle problem domain, so they can be applied to other domains Advantage: Code can become part of a class library and used for other purposes
Example Class Definition in C++ class SolverInfo { private: Problem problem; public: SolverInfo(Problem p); void solve(); private: static String promptActionName(); };
Notes On the "SolverInfo" Class Q: Why ``SolverInfo'' and not just ``Solver''? Because Solver will be defined to be a pointer to a class object SolverInfo No methods are defined in-line (defined in a separate file) No data members are public All public methods are part of the class interface
Example Main Program #include "ProblemInfo.H" #include "SolverInfo.H" int main(Integer argc, StringArray problemArgs) { Problem p = new ProblemInfo(problemArgs); Solver s = new SolverInfo(p); s->solve(); } Note that this program makes no mention of the 8-puzzle, and thus could be used on other problems suitably defined.