Anda di halaman 1dari 5

Software Engineering, CPSC-4360-01 and CPSC-5360-01 Tutorial 1.

Answers
Exercise 1. (Farmer and Cow, Created by Centre for Instructional Technology, NUS, with the support of Dr. Bimlesh Wadhwa, Gerald Ng, Prasad Iyer, adapted from an example of Gary K. Evans, www.evanetics.com) Once upon a time, there was a farmer called Jones. He owned a cow called Bessie. Everyday morning, he would milk his cow and sell the milk to the Milk Collection Centre (MCC). The MCC also collect milk from other farmers. Define a model for this application requirement: On a particular day, find the total milk collected from the farmers. Any cow accepts to be milk only by its owner. Try to model this application under the procedural approach and object-oriented approach. Answer. Here it is a comparison between modeling using procedural and object-oriented techniques. 1. In the procedural world, we would have a function Milk( ): float Milk (struct cow, float amount); To milk a cow (i.e., remove milk from it):
struct cow { char name[30]; float currentMilkVolume; const float maxMilkVolume = 5.0; //assume gallons }; struct Cow Bessie = {Bessie, 4.0}; // . . . other code here . . . // now . . . milk the cow fReturned = Milk (Bessie, 1.3);

Let us do some analysis of this implementation: The Milk( ) operation is stand-alone, because there is no requirement that a Farmer does the milking. Milk( ) must be told through a parameter what cow to operate on. This is error-prone. Milk( ) must directly access the struct contents, because Milk( ) is, therefore, coupled to the struct. The conclusion is that, in the procedural world, the milk is taken directly from the Cow (i.e., a language data structure is directly manipulated), and there is no concept of a Cow as an intelligent entity. 2. In the object-oriented world, milking a Cow may involve the entities (also called classes) Farmer, and a Cow. The relationship is that a Farmer, say Jones, is responsible for a Cow. Obviously, there are many benefits of the object-oriented model against the procedural one, such as: - if there is a change to the way the cow determines how much milk to yield, then these changes to implementation are hidden behind the public interface. Moreover, if the interface is not disturbed, the Farmer is unaware of any change. Of course, if another farmer has to milk the cow, a possible solution is to provide to that farmer the cows interface, so that he can milk the cow, too.

Compared to the procedural world, any potential farmer would have to contain code to do the milking. Instead, in the object-oriented world, the milking code is in the Cow, that is in one place for reuse. Let us now do the design of the object-oriented model. In the real world we say the Farmer milks the cow, so the Farmer owns the result of Milk(amount). Since the farmer is doing the milking, a first attempt is to put the Milk( ) operation in the Farmer class. However, if an application invokes Farmer.Milk( ), this operation cannot milk the cow, because it is a Farmer operation, and the milk is in the cow, not the farmer! This does not make any sense, because Farmer.Milk( ) still has to access a Cow-scope operation. Therefore, we proceed to a different approach, namely to put Milk( ) directly in Cow. Now the Farmer invokes the Cow.Milk( ) operation in order to obtain the milk. All the struct information (the data) is hidden inside Cow. So, in the object-oriented model the Farmer doesnt take milk from the cow. The Farmer asks the Cow to milk itself. That is, the Cow manipulates its own data values. The analysis model for it is: The Milk( ) operation is part of Cow, so in the absence of Cow, there is no Milk( ) operation. The Milk( ) operation does not have to be told what Cow to operate on, so every Farmer is milking his own Cow. The Milk( ) operation is an opaque interface, and hides the implementation of Cow from Farmer. In conclusion, in the object-oriented world, the milk is requested from the Cow, and the Cow determines how much to yieldmaybe none! In order to see that class Cow is the most important one, we wrote the following series of questions/answers. a) Who should know how much milk the Cow has? The cow. b) Who should know how to determine whether the Cow is even milkable at the time of the request? The cow. c) If the Farmer asks for 3 gallons, and the Cow only has 2 gallons to offer, who should determine if 2 gallons, 1 gallon, or 0 gallons, is returned? The cow. d) Whos state might change with the invocation of the Milk( ) operation? The Cows state changes, not the Farmers. The Cow may give up the 2 (i.e. the maximum) gallons she has, and then transition to the unmilkable state until a new store of milk is generated. The Farmer has a bucket of milk that he didnt have before, but his state has not changed. Recommendations: Dont get too distracted by reality. A literal translation of the way the real world works, and the way we talk about it working, are often an impediment to software modeling and implementation.

Here it is a possible complete Java code for this problem (this is only to make an image of how this course is about).
class Farmer { private String name; private Cow c; { public void setFarmer(String n, String cowName, double initialAmount) this.name = n; c = new Cow(this, cowName, initialAmount); } void milkTheCow(double amount) { c.milk(amount); } void display() { c.displayMilk(); } { Farmer f; String name; double currentMilkVolume; final double maxMilkVolume = 5.0;

class Cow private private private private

protected Cow (Farmer f, String name, double initialAmount) { this.f = f; this.name = name; if (initialAmount > maxMilkVolume) System.out.println(name + ": I cannot have so much milk!"); else currentMilkVolume = initialAmount; } public void milk(double amount) { if (amount > maxMilkVolume || currentMilkVolume < amount) System.out.println(name + ": I don't have so much milk!"); else currentMilkVolume -= amount; } public void displayMilk() { System.out.println(name + ": I have now " + currentMilkVolume + " gallons."); } } public class Milking { public static void main(String args[]) { Farmer f1 = new Farmer(); f1.setFarmer("Jones", "Bessie", 4.0); f1.display(); f1.milkTheCow(1.3);

//

f1.display(); f1.milkTheCow(4.3); f1.display(); f1.milkTheCow(2.2); f1.display(); Cow c2 = new Cow("Cow2", 5.0); Farmer f2 = new Farmer(); f2.setFarmer("Farmer2", "A new Bessie", 4.0); // f2 has a different cow object with the same name f2.display(); f2.milkTheCow(2.2); f2.display(); f2.milkTheCow(0.3); f2.display(); }

Exercise 2. (Genericity versus custom, [Sommerville, 2007], Exercise 1.2, page 18) What are the differences between generic software product development and custom software product development? Answer. The main difference lies in the end user of the software product. Generic Software Product: Product specification owned by product developer The client is not the end user, who may not have a good understanding of what the end user really want Has a much wider end user base, i.e., harder to anticipate all possible usage Should concentrate on user friendliness, broad features base Should involve more tester, e.g., beta test Custom Software Product: Product specification owned by client

Client is the end user. Should have a much better understanding of the actual requirement. Should concentrate on efficiency, robustness as usage can be predicted more accurately. Should involve the client in testing. Incremental process possible.

Exercise 3. (Software Engineering Myths) Discuss the following software engineering myths: 1. A general statement of objectives is sufficient to begin writing programs - we can fill in the details later. 2. If we get behind schedule, we can add more programmers and catch up. 3. Project requirements continually change, but change can be easily accommodated because software is flexible. Answer. Regarding the first statement, it is good to start writing programs. On the other hand, it is important to discuss important details from the beginning of the software development. Therefore, poor up-front definition is the major cause of failed software efforts. Regarding the second statement, it is good to have a considerable number of programmers to work as a team. However, it is recommended they to start together from the beginning because adding programmers to a late project makes it even later (because the new added programmers should be aware of the previous work, etc). Regarding the last statement, it is true that software is flexible compared with hardware. On the other hand, if the program requirements change when the project is already in the late phases of software development (e.g., implementation, testing), then the cost impact is severe.

Anda mungkin juga menyukai