Download presentation
Presentation is loading. Please wait.
1
Introduction to Software Design
EE 312 Software Design and Implementation I
2
Software Engineering Goal
Production of software that is effective and reliable, understandable, cost effective, adaptable, and reusable Because of the long lifetime many people will be involved Creation Debugging Maintenance Enhancement Two-thirds of the cost is typically beyond creation Understandability is also important because of the long lifetime of software. A software product usually evolves over time. Software engineers who had nothing to do with its original development often make enhancements and fix bugs (errors). This process is called software maintenance. As a measure of the difficulty of maintaining software, experts estimate that two-thirds of the cost of developing software is devoted to maintenance. This cost can be reduced when the design and operation of a system are comprehensible.
3
Design Principles Abstraction Encapsulation Modularity Hierarchy
4
Principles Determine the relevant properties and features while ignoring nonessential details Abstraction Encapsulation Modularity Hierarchy Abstraction is the process of determining the relevant properties and features of an object while ignoring nonessential details. The relevant properties are defined by how the object is to be used and manipulated. For example, an auto salesperson views a car from the standpoint of its selling features, while a mechanic views the car from the standpoint of the systems that require maintenance. If you are concerned with developing a help system to assist car owners who do their own repairs, you need to be sure that the mechanic’s view is considered. 2001 PT Cruiser Photo/Courtesy of DaimlerChrysler Corporation.
5
Separate components into external and internal aspects
Principles Separate components into external and internal aspects Abstraction Encapsulation Modularity Hierarchy Encapsulation or information hiding is the process of separating the component of an object into external and internal aspects. The external aspects of an object need to be visible to other objects in the system. The internal aspects are details that should not affect other parts of the system. Hiding the internal aspects of an object means that they can be changed without requiring changes to other system parts.
6
Principles Construct a system from components and packages Abstraction
Encapsulation Modularity Hierarchy Most complex systems are modular. They are constructed by combining simpler working components or packages. Proper modularization of a complex system also helps manage complexity. Breaking things down into smaller, easier to understand pieces makes the larger system easier to understand. For example, an automobile can be decomposed into subsystems. Automobile subsystems include a cooling system, an ignition system, and an exhaust system. By thinking about an automobile in terms of its subsystems, we can grasp more readily the car’s overall structure and operation.
7
Ranking or ordering of objects
Principles Ranking or ordering of objects Abstraction Encapsulation Modularity Hierarchy A ranking or ordering of objects based on some relationship between them is a hierarchy. Hierarchies can help us understand complex organizations and systems. Figure contains a partial organizational chart for the management of a company. The chart shows the management hierarchy based on the relationship of who reports to whom. The hierarchy helps employees understand the structure of their company. A useful way of ordering abstractions is from most general to least general. A hierarchical ordering based on natural relationships is called a taxonomy. Such a hierarchy makes all the abstractions easier to understand because it exposes the relationship of the characteristics and behaviors they have in common. For example, consider a taxonomy of musical instruments that organizes instruments by how they produce their sound. Idiophones: Solid instruments that are intrinsically sonorous, e.g., bell and cymbal. Membranophones: Instruments with taut membranes, e.g., drum and tambourine. Aerophones: Instruments that enclose and free masses of air, e.g., trumpet and saxophone. Chordophones: Instruments with stretched strings, e.g., lyre and violin. Electrophones: Instruments with oscillating electric circuits, e.g., synthesizer and electric piano.
8
Abstract Data Types (ADT)
A specification of a set of data and the set of operations that can be performed on the data. Independent of concrete implementation Uses defined interface Hides details from the user (information hiding) Not the same as a data structure
9
ADT Example -- Stack bool empty() E peek() E pop() push(E item)
Tests if this stack is empty. E peek() Looks at the object at the top of this stack without removing it from the stack. E pop() Removes the object at the top of this stack and returns that object as the value of this function. push(E item) Pushes an item onto the top of this stack.
10
Why? Allows implementation to be changed without violating ADT definitions Gives a standard list of structures to use and study Building blocks and tools Foundation for OOP Abstraction, Encapsulation, Modularity, Hierarchy
11
Object-Oriented Design
Purpose Promote thinking about software in a way that models the way we think and interact with the physical word Including specialization Object Properties or attributes Behaviors Now let’s analyze this activity. First, you recognized the need for action—having to get up early and deciding that the clock radio could help meet that need. So you go over to the clock radio, which is a physical object. This object has properties like weight and size, and it also can do something. For one it can play music at an indicated time. It’s not necessary for you to know entirely how the clock radio works. You need to know only which switches and buttons to use. The switches and buttons are the interface to the clock radio. If you understand the interface to an object, you can use it to perform some tasks without understanding how the object works internally. Moving the appropriate switches and pushing the appropriate buttons are signals to the clock radio to modify its behavior. Such interactions are so routine that it is easy to overlook how amazing this activity is. You were able to make an object perform a complex activity without understanding the internal operation of the object. You were able to do so because you had an appropriate abstraction of the object. Indeed your mental abstraction of a clock radio means that when you travel and stay at a hotel room, you are able to set its clock radio even though it is a different clark radio. Similar objects often exhibit similar behavior. This way of dealing with the complex world around us also can be applied to software design and programming. A key step in developing a complex system using object-oriented design is to determine the objects that constitute the system. By carefully creating appropriate abstractions of these objects and separating their internal implementation from their external behavior, we can manage the complexity of a large software system. So what exactly do we mean by an object? Physical things are certainly objects. A ball, a file cabinet, an address book, a tree, and a computer all are objects. What about things like a word, a bank account, or a musical note? These things are not physical objects, but they are objects—in the sense that they have attributes and properties, and we can perform actions on them. A word has a length and meaning, and if we are talking in regard to a word processor, a word can be inserted or deleted from a document. A bank account has a balance to which funds can be deposited or debited. A musical note has pitch, duration, and loudness and can be played. For the most part, something is an object if it has a name, properties associated with it, and behaviors such as message handling. Typically, when an object receives a message, the message causes the object either to take some action or to change one of its properties. Continuing with our clock radio example, when you push the “music on” button, the current broadcast is played. If we are going to take an object-oriented approach to developing software, it makes sense to use a programming language such as Java that supports thinking and implementing solutions in terms of objects. A language with features that support thinking about and implementing solutions in terms of objects is an object-oriented programming language. Using an object-oriented programming language to implement an object-oriented design is called object-oriented programming. Notice we were very careful to include the phrase “implement an object-oriented design.” As you will see later, you can use an object-oriented language, but not think in terms of objects.
12
Programming Class Object Term for a type of software object
An instance of a class with specific properties and attributes Using an object-oriented programming language to implement an object-oriented design is called object-oriented programming. Notice we were very careful to include the phrase “implement an object-oriented design.” As you will see later, you can use an object-oriented language, but not think in terms of objects. Programming languages generally give programmers the ability to specify the types of objects to be used in their programs, where a type is a collection of values and the operations that can be performed on those values. An example of a type would be the set of integers and the arithmetic operations that can be performed on them. Object-oriented languages provide programmers the ability to create a type known as a class for representing the properties and message-handling behaviors of a type of object. Classes normally are organized so that the manipulation of a property is handled via a message to the object. Thus, the class encapsulation process is similar in nature to the process of designing a car radio, which has interfaces for both its user and to the electrical system. Programmers use a class to create instances of it. An instance is an object with a particular value for each property and attribute of the class. In practical terms, a class can be thought of as a model or template for an object. From the class, objects with specific properties can be created, or instantiated. An object is an instance of exactly one class. As another example, consider a star-shaped cookie cutter. When it is pressed into dough, a cookie is formed. The cutter corresponds to a class—it is a cookie mold. An individual cookie is an object—it is constructed using the cookie cutter. The difference between a class and an object is subtle but important. Whereas a class is a concept, an object is a concrete entity, it is a specific instance of a class. For example, the concept of a car corresponds to a class, but the particular SUVs you may see driving down a street are objects. Similarly, the notion of a bank account corresponds to a class, but your savings account is an object. We can use a class type to represent playing cards. The properties of a card would be its rank and suit. Card message handling would include methods that queried an object regarding its rank value and suit value. The queen of clubs and the nine of diamonds would be playing card instances or objects. Another important feature of object-oriented languages is that they let programmers exploit the similarity of objects to derive new types of objects from existing types of objects. In this situation, we call the old type, the superclass and the new class a subclass. The subclass both extends or specializes the functionality of the superclass and inherits the properties and behaviors of the superclass. Specialization is something we see all the time. For example, a poem, novel, biography, and office memo are all types of writing with specialized attributes. An example in Java is the graphical superclass for representing the attributes and behaviors expected of any component that can be placed in a window. The superclass is used as the basis for deriving specialized components such as buttons, menus, scroll bars, labels, and text entry areas. As another example, an aquarium simulation is developed in Chapter 12. The superclass for the simulator is a standard Java class rendering (drawing) images. A snapshot of the application is given in Figure 1.12.
13
Programming Problem solving through the use of a computer system Maxim
You cannot make a computer do something if you do not know how to do it yourself
14
Problem Solving Process
Determine Analysis problem features Rethink as appropriate Describe objects Design and methods Produce the Implementation classes and code Examine for Testing correctness
15
Tips Find out as much as you can Reuse what has been done before
Expect future reuse Break complex problems into subproblems Find out what is known about the problem Talk to the presenter Determine what attempts have succeeded and what attempts have failed
16
Preconditions and Postconditions
Frequently a programmer must communicate precisely what a function accomplishes, without any indication of how the function does its work. Throughout the book, preconditions and postconditions are used to specify precisely what a function does. However, as we will see, a precondition/postcondition specification does not indicate anything about how a function accomplishes its work. This separation between what a function does and how the function works is extremely important - particularly for large programs which are written by a team of programmers. Can you think of a situation where this would occur ?
17
What are Preconditions and Postconditions?
One way to specify such requirements is with a pair of statements about the function. The precondition statement indicates what must be true before the function is called. The postcondition statement indicates what will be true when the function finishes its work. There are many ways to specify the requirements for a function. In this class, and in the textbook, we will use a pair of statements for each function, called the function's precondition and postcondition. As we will see, the two statements work together: The precondition indicates what must be true before the function is called. The postcondition indicates what will be true when the function finishes its work. An example can clarify the meanings...
18
... Example void write_sqrt( double x) // Precondition: x >= 0.
// Postcondition: The square root of x has // been written to the standard output. ... This is an example of a small function which simply writes the square root of a number. The number is given as a parameter to the function, called x. For example, if we call write_sqrt(9), then we would expect the function to print 3 (which is the square root of 9). What needs to be true in order for this function to successfully carry out its work? Since negative numbers don't have a square root, we need to ensure that the argument, x, is not negative. This requirement is expressed in the precondition: Precondition: x >= 0. The postcondition is simply a statement expressing what work has been accomplished by the function. This work might involve reading or writing data, changing the values of variable parameters, or other actions. Notice that the information shown on this slide is enough for you to use the function. You don't need to know what occurs in the function body.
19
Example Which of these function calls meet the precondition ?
write_sqrt( -10 ); write_sqrt( 0 ); write_sqrt( 5.6 ); So, here are three possible function calls. Two of the calls meet the precondition and have predictable results. In one of the calls, the precondition fails, and the result of the function call is unpredictable. Which function call is the trouble maker?
20
Always make sure the precondition is valid . . .
The programmer who calls the function is responsible for ensuring that the precondition is valid when the function is called. So, let's look at the use of preconditions and postconditions in a typical situation. The programmer who calls the function is responsible for ensuring that the precondition is valid when the function is called. If she fails in this responsibility, then all bets are off. There is no telling what might occur.
21
. . . so the postcondition becomes true at the function’s end.
The programmer who writes the function counts on the precondition being valid, and ensures that the postcondition becomes true at the function’s end. On the other hand, if she keeps her end of the bargain, and calls the function with a valid postcondition, then the function has a responsibility of its own. The function must complete its execution (no infinite loops), and when the function finishes, the postcondition will be true. In some ways, you can think of the precondition/postcondition statements as a contract between two programmers: One programmer (who uses the function) is guaranteeing that she will make sure that the precondition is valid before the function is called. The other programmer (who writes the function) is going to bank on the precondition being true. This other programmer is responsible for making sure that the postcondition becomes true when the function finishes execution.
22
On the other hand, careful programmers also follow these rules:
When you write a function, you should make every effort to detect when a precondition has been violated. If you detect that a precondition has been violated, then print an error message and halt the program... ...rather than causing a disaster. And such detections can also avoid disasters.
23
... Example void write_sqrt( double x) // Precondition: x >= 0.
// Postcondition: The square root of x has // been written to the standard output. { assert(x >= 0); ... Here's an example of how you would write a friendly function which detects when its precondition is violated. There is no need for anything fancy when the precondition fails: just print an informative error message and halt the program. In this example, I have used the C++ assert function, which has a logical expression as its argument. If the expression is true, then the assert function does nothing. But if the expression is false, the assert function prints a useful message and halts the program. You can read about the full details of the assert function in Section 1.1 of the text.
24
Advantages of Using Preconditions and Postconditions
Succinctly describes the behavior of a function... ... without cluttering up your thinking with details of how the function works. At a later point, you may reimplement the function in a new way ... ... but programs (which only depend on the precondition/postcondition) will still work with no changes. Here are the primary advantages to using a method such as preconditions/postconditions to specify what a function accomplishes without giving details of how the function works. One of the important advantages has to do with reimplementations. Often a programmer will think of a better method to accomplish some computation. If the computation is part of a function that includes a precondition/postcondition pair, then the function can be rewritten and the new, better function used instead. Any program which uses the function (and which only depends on the precondition/postcondition contract) can use the new improved function with no other changes.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.