From Analysis To Coding





Step 1 - Describe Your Classes

    In the first stages of analysis and design, you'll want to review the task at hand several times and attempt to come up with only a rough idea of how you want to decompose the problem. Remember that testing it always much easier if you can test incrementally, and objects lend themselves perfectly to this concept. Get a high-level idea of what will be passing information and to whom in order to accomplish your goal.

    A) What classes do I need?

    Decompose your problem into objects that can interact with each other to simulate what it is you are trying to represent or accomplish. Remember that there are several ways to do this. For example, if you need to simulate a person crossing a street, then you may want to have a street object, a person object, and several car objects.
    Alternatively, you could have several traffic lane objects representing the street. Since cars and busses and bikers are all obstacles, then maybe you will want them all to inhereit from a LaneObstacle class? The choice is entirely up to you.
    You should choose a representation that will be logical enough to understand and program, but simple enough that you aren't going "overboard" with objects. After all, you could make the Car objects contain Seat objects, Windsheild objects, Headlight objects, Bumper objects, and more. But this level of detail doesn't seem important just for the task of crossing a street.

    B) What methods do my classes need?

    For each classe, you should consider further exactly how the object is supposed to interact with other classes and objects, or even just with itself. If information is being passed from object to object, then it may be a good idea to have accessors and mutators. Stay at a high level, but try to walk through the actual execution process in your head to see where objects may need to perform tasks.
    In the case of a person walking across the street, you will probably want a method that checks to see if the street is clear of traffic, and also a method that actually walks across the street. Finally, you can have another method that sits and continuously checks for traffic with the first method, and when clear will call the method actually crosses the street.

    C) What data do my classes need?

    For each class, you should look at the methods that the class has in it, and choose data members that will enable those methods to perform their taks. Many list objects have a data that keeps track of the size of the list. This way, the list can answer questions about size much faster by looking at the value of its data rather than iterating through the whole list and counting up how many were there.



Step 2 - Modify and Type Your Data Members

    For each data member that you need, you now need to choose, based upon how you are going to use them, the types and modifiers of your data. If you have decribed your data mebers well, and have a firm grasp on who will use those data and how, then this part should be easy.

    A) Type

    Good programming prcatice dictates that you should use the smallest data type you can to represent your information. This means that ints are better than doubles if you never need decimals. In addition, using primitives is generally better using object references. However, objects can provide for specialized methods that primitives don't offer.
    One exmaple of this is for representing a dek of cards. You can create a class called Card that will contain data members about the suit, color, and number of the card and provide accessors and mutators such as getNumber() and setSuit(). This is a perfectly good way of representing cards, and you are encouraged to use objects to help decompose problems.
    However you should realize that you can also represent cards with ints in the following way: Each int is a three digit number. The hundreds will be either 1, 2, 3, or 4 and will represent the suit. The last two digits will be between 1 and 13, and can represent the numbers of the cards from Ace to King. To retreive the suit, you can use integer division by 100. The number of the card is modulo (%) 100.
    While both representations give you effectively the same amount of information, the true object-oriented approach is more manageable and less susceptible to errors, but the numeric approach uses less space and runs faster. It is always a trade-off, and it will be up to you to decide which representation best serves your purposes.

    B) Class or Instance?

    The next step to decide is whether or not your data is class data or instance data. Class data belongs to class, so only one copy of that data gets made, and all instances must use this exact same copy of the data. Instance data is where each instance has this data field of their own.
    You can imagine that things like names, ID numbers, and current capacity levels are all instance data. That is, every different Person object should really have their own name. It would be quite embarrasing if all people had the exact same name. Other common fields such as maximums and minimum values, that apply to every instance and are the exact same value for each, are class data.
    If you were making a Card class, then you could include class data for a minimum number (1), and also a maximum number (13), and then every Card instance could make sure that its own instance data numbers are between the minimum and maximum class data numbers.
    Remember: Not all books should have the same title and not all cars should have the same liscence plate number. Usually things will be instance data so that they can be separate and unique for the others. Only specific values that all instances can share should be made class data.

    C) Constant or Variable?

    Choose the mutability of your data member. If, when you run your test programs, your data member will be assigned one unchanging value throughout the entire test, then you should make your data member a constant. In general, only data members that have a good reason to change (or whenever it just makes sense for that member's value to be able to change) should remain a variable member.
    For example, the prices of the stock market are expected to and certainly do change very frequently. The list of all of the countries around the world doesn't change very often, but it still changes. These should be made variables. However, the number of months in a solar year will never change, and this value should be made a constant.
    However, if it is an instance member and you cannot assign it a value immediately upon object instantiation (in the constructor), then JAVA will not allow you to decalare your data member as a constant.

    D) Public or Private?

    After considering how the data will behave, you should turn your attention to who will have access to it, if anyone? If you don't want outside classes to access data, you should make it private. If you beleive, however, that giving other classes access to your data will not risk the correctess of your program, then you can go ahead and make those members public.
    In general, class constants, since everyone will use them but they can't change the value, are safe enough due to their class and constant status to be made public. However, it is good object-oriented programming doctrine never to allow any more access to members than is strictly needed.
    You can think about visibility access in the following way: Imagine two roomates. One roomate wants to borrow the other roomate's music. You must decide whether the first roomate will walk across the room and simply take the music (public access), or if he must simply ask the other roomate to please turn the music on. That way, he can still hear the music but he won't get near enough to cause potential damage (private access with a public accessor method).
    Becasue a class' or an instance's data may be accidentally changed to carelessness, it is usually the safer idea restrict access as much as possible, and then allow accessors and mutators only as necessary.


Step 3 - Describe Your Method Members

    Each method will be used to provide the class or instance to which it belongs with more functionality. The key to programming well is to break your goal up into manageable, repetative smaller taks that can be combined in some sequence to get you to your goal.

    A) The Task

    For your method, decide what that method is supposed to do for your program. Is it supposed to make a simple calculation and change the values of provided data? Is it an accessor method that is supposed to return the value of the data? Is it supposed to generate a new number for use and return it? If so, what type (int, boolean, Object reference) is it supposed to return?

    B) Necessary Inputs for the Task

    Now that you know what must be done, look at the resources that your method will need to do it. For instance, most public and private data members are readily available (unless this method becomes a clas method). Any other data, however, may need to be passed in from an outside source. For each different peice of information that your method needs that it can't already use, decide the type of that information and the order that you want your information passed to your method.

    C) Class or Instance?

    The main difference between a class method and an instance method is that class methods cannot access and instance data or use and instance methods. This preserves the concept that the method will be entirely devoted to the whole class, and not tied to any one particular instance.
   
    D) Public or Private?

    Based upon what purpose the method serves, choose which objects are the most likely candidates to call upon the method. Again, a restrictice doctrine is suggested. If it doesn't make sense for outside objects to call a particular method, declare that method with private accessibility. However, if the method provides a return value that is useful to another object, then you should declare the method with public accessibility.
    To give an example, reconsider the scenario of a person walking across a street. It just doesn't make much sense for a street to call a walk() method on a person. Normally, the person decides for themselves whether or not to cross. Therefore, the walk() method would be declared private inside the Person class.
    On the other hand, the person may call a method, getNumberOfLanes() on the Street object, becasue that method could potentially provide useful information to the person when they choose whether or not to try crossing the street. In this case, the method getNumberOfLanes() would be declared public inside the Street class.

    E) Outlining the Tasks

    Finally, you must describe how, exactly, your method will accomplish it's goals. Pseudocode, which is a form of code shorthand, can be helpful to get the main ideas across. For example, the decision process for crossing a street may look something like this:
private boolean shouldCross(Street s) {
        for all lanes in the street {
                check if that lane is clear;
                if not, then return false;
        } otherwise
                return true;
        }
    While this is clearly not actual code, you can still tell a lot from this "pseudocode". For example, it is clear that you will need the Street instance, and from that you will need an accessor method for the lanes. Furthermore, each lane will need to have a public method that returns whether or not it is clear. This sort of analysis helps to see where you may have missed important methods or parameters. Furthermore, the method itself will involve loops and control statements.


Step 4 - Constructors

    Now that yoiu have your data methods planned out, you shoul dbe able to decide how you want to instatiate your object. That is, what data members do you want to initialize, and with what values, and are there any private methods that might be worth calling?
    Remember that all of your data members will be given default initialization values based upon their type. Numeric primitives are assigned 0 (or 0.0), and object reference types are assigned the JAVA keyword null value. However, the choice is yours as to how to best initialize your data members. If you want the initial value to be chosen at the time of the object creation, then you must have these values passed in to your constructor as arguments.
    You can have as many constructors as you want, and all with different ways of initializing some or all of your members (provided they have unique signatures). You can even take in another instance of the same class and use its data to make a carbon copy of the source instance. (See Object.clone()).

Step 5 - Draw Your Complete Class Diagram

    For each class, use the proper diagramming rules for all of your members to generate your class diagrams. Examples of most of the different types are shown below, next to their corresponding diagram.

Verbal DescriptionCorresponsing Diagram


Step 6 - Write Your Class Definitions

    For each Class that you have in your program design, start a separate source file (.java file) with the exact same neame (case sensitive) as your Class name. For instance, a class called List would be declared in a file called List.java.
    Again using the rules to determine is keyword modifiers are necessary, follow the scheme below to declare and define your class file. Remember to use appropriate naming conventions, follow all style guidelines, follow all commenting guidelines.. If you need help with the syntax of declaration statements, you can look here. There's a fantastic example of coding using incremental development called BMICalculator which I highly recommend looking at.

ClassName.java
                        < FILE HEADER >


< Class Header >

public class ClassName {

    < class constant data declarations and assignments >

    < other data member declarations >

    < constructors >

    < public and/or class method declarations and definitions >

    < other method declarations and definitions >

    < the toString() method (for instantiable classes) >

}



    Remember, when you declare and define your classes, to keep incremental development in mind. A good first step is to write a working (compilable and instantiable) class definition that only has a single default constructor. When you write your test program (the class that has the main method), you can simply print out "Hello, World!" and nothing else. After you have this tiny part of working code, you can then slowly build up to the full class definition and test program (two separate things) one method or one test at a time. Use frequent print statements to help you debug.
    If you need help, feel free to ask an on-duty consultant in the instructional labs, or email your lecturer. We're here to help you break these assignments down into small, manageable chunks. Good Luck!