Full Transcript

[Chapter 2: The Object-Oriented Design Process] =========================================================== - Software development process focuses on requirement analysis, object-oriented design, and implementation - For each stage: learn what is input to the stage and output from the...

[Chapter 2: The Object-Oriented Design Process] =========================================================== - Software development process focuses on requirement analysis, object-oriented design, and implementation - For each stage: learn what is input to the stage and output from the stage so that it can be used for input for the next stage - We also learn systematic tools used for each stage - Requirement analysis means we understand & identify the problem we need to solve - Problem found and identified: solve the problem through design - Once problem solved, we implement solution using a high-level language - **First stage is problem identification and solving the problem and implementing the solution** - Input for requirement analysis is the **client request** - Non-technical; client may approach you with a problem (like having a calendar, voice message system, etc) - Very vague; designers identify the requirements for the client's request - **Functional requirements**: significant or important functions or operations the system has to support. When system is running, the user can expect functions from the system - **Example**: voicemail system expects login, listen message, leave message, manipulate message (save, delete, quit) - Functional requirements are found using **use cases (a tool used to find functional requirements)**; not a random process - **Non-functional requirements**: criteria to judge the quality of functional requirements. In other words, the performance (response time), operational cost, etc are assessed to see its quality - For example, seeing how fast a message is sent - If we identified 10 use cases → 10 functional requirements (1 to 1 ratio for each use case) ![](media/image2.png) - Important features of use cases: - Step \#s for first column of table - Second column is the user's action - Third column is the system's response - **Important requirements** - Always initiated by the user, so the second column should **not be empty!!** - Use cases should **describe the interaction between the user and the system** - Dial number → system should respond - At the end of the use case, the **goal should be achieved.** - Simple user action is something like dialing a number and is not a use case - **Requirement specification**: once requirements are identified, officially document the requirements in the specification (figure out problem to solve) - Client and developer check the requirement specifications and sign on it; rest of project can rely on specification - Should be complete; completely define tasks to be performed - Should not have contradictions - Should be reviewable and testable - Set of use cases **is not equal** to functional specifications - **Once you identify functional requirements, officially document them in functional specification** - Design: to find a solution for a given problem - Multiple ways to find a solution using different design methodologies (functional, component, event-driven, etc.) - **We solve the problem using an object-oriented way using classes/interfaces that are required, what responsibilities are, and how we assign them to the classes and interfaces we identified, how the classes and interfaces are related (the relationships) → follow to design software in object-oriented way** - Noun/Verb CRC (**class responsibilities and collaborations**) are tools that allow you to identify classes, interfaces, and their relationships - After CRC is done, we are given a set of classes, responsibilities to achieve these two goals. Collaborations help identify the relationships - Once you find out the classes and interfaces, responsibilities and relationships, we need to document them - Programmer, designer, implementor can be different programmers - What we identify as our solution should be documented as a result so that they can be delivered to the implementor & can be implemented in a high-level language - **UML diagrams**: can draw different diagrams like class diagram, sequence diagram, state diagram - **Javadoc**: documents public interfaces for your program - Design of solution should be documented after design is complete - Two design documentation tools: UML diagrams and Javadoc - When we look at API Java and look at public interfaces of classes, it is formatted in a frame form - When clicking ArrayList link, displays all constructors available for a method - **Can write Javadoc so that it will show classes in an HTML format for public interfaces** - **Vague client requirements will evolve to a working and running application program** - **Note: implementation should be addressed AFTER design is done** - Programmer implements the design based on the UML diagram and Javadocs [2.2 - Objects and Class Concepts] - In real world: - Objects represents anything in real world that can be distinctly identified (computer, desk, person) - Class represents set of objects w/ similar characteristics and behavior - **Representation in Our Model (more technical)**: - Object has an **identity, state, and behavior** - Identity allows you to access an object; essentially the **reference** - **When we create a new bank account using new keyword,** will create a **bank account object** somewhere in the memory heap and will return a reference (the **memory address)** - After creating it, it will return the reference (**memory address)** of the object - Store memory address in a variable such as **b** - When we mention the bank account afterward, it will return that specific bank account's balance ![](media/image4.png) - **State** is the current value of the instance variable - If the balance is 100 for example, the bank account has \$100 in its current state because instance variables are per object; instance variables represent the state of the object - **Behavior** are the methods we can use on the object Suppose we have a new bank account: - B1 would be a different object which may have \$100 or \$200 depending on the state of the bank account w/ reference of 1111 - B2 would reference 1111; referencing same object as B1 ![](media/image6.png) - == compares the identity, while.equals compares the content - If we use ==, we **compare references (we see if two objects reference the same memory address); also compares its identity** **Examples:** - If we use.equals, it compares if the **content** is equal (compares the **state)** **Examples:** ![](media/image8.png) - java.lang.Object is the mother of all existing objects in Java - If a class does not extend anything explicitly, it automatically extends the Object class; **all objects directly extend Object** class - **This implies that whatever is defined in the class is inherited to all Objects** - In other words, Object class **directly inherits** all existing objects created in Java - Example methods inherited: toString, equals, clone, hashcode - **Note: when java.lang.Object defines these methods, the methods are defined in a primitive way** - **Body are defined to satisfy general object functions** - **We need to \@Override the.equals method if we need to compare our own objects for example** [Noun/Verb Analysis] - **Once design is done, must document design in form of UML diagrams and Javadoc to pass to implementor** - Before doing noun/verb analysis, we have requirement specification - Find specific and significant nouns from requirement specifications (noun analysis) - These will be your initial set of classes - Nouns will transform to your classes - Once we find initial set using CRC, we refine the classes to finalize it using CRC - **Once you find significant nouns, write them down & consider them being translated to initial set of classes** - Once you identify initial set using CRC technique, we refine the classes - Whatever comes to mind, put them in initial set - Significant verbs become responsibilities of classes - Assign verbs to classes we identified so they transform to responsibilities of that class - For given functional description, find **nouns** and form initial set of classes - Examples are like the Mailbox, Message, Telephone, etc - Next, think about classes that are not explicitly stated in functional requirement specification - What can be required to solve the problem (like where messages are stored) - Design set of classes should be your own classes; if we use storage given by library for example, do not include in design - If we are using user-defined storage (like message that is stored in a specific manner), we have customized storage (like a queue) [2.3 - Identifying Classes] - Look for nouns - Although we do not see them explicitly in the functional requirement specification, think about what is required to solve the problem (can think about it) - If we need storage, what kind of storage? - If we use existing storage from library, do not need array list in design - In design: should be set of classes we come up with - If we want user-defined customized storage that handles messages, we put it in the design [Class Categories] - Check if we are missing tangible things; things that are easily identifiable in the problem - They appear on functional requirements; include if not (will have them most of the time) - Agent classes: if application uses some logically related functions frequently, put the methods in one class so whenever we need a method, we use the class - Useful to convert operation of class to an agent class sometimes - Has characteristics around action it carries out - We use agents often to decouple operations from a class - Example: Scanner class reads data from standard input. Any method that reads input from keyboards and files are encapsulated inside the scanner class; do not need to define this method. Create scanner object to read data - Events and transactions: event objects will remember the past; uses past information in the present - Example: Mouse event class from Java Standard Library - If we draw a car and when you click the car and click somewhere else on the screen, the car moves - Event is mouse pressed; MouseEvent remembers the mouse point - From each mouse event, can retrieve mouse point and can calculate the distance; user sees that mouse moves from location to location - User and role: used to establish different users w/ different roles and permissions of a system - Administrator, Reviewer classes for example - Missing these classes: add to set - Systems: high level classes that represent high-level systems - Models a subsystem or overall system being built - Used to initiate and terminate the system - Example: MailSystem class; high-level responsibilities like initializing MailBoxes, terminating the mail system, etc. - Not involved with low level services, like keystrokes - Deals with high-level responsibilities (terminating mail system, initializing mailbox) - System interfaces: lies between application and operating system; hides system interface class - Hides details of OS so application can be simplified - Display windows, input readers, output files, etc. - Files saved in OS and located in system - File class from library hides details of file system in OS - If we want to read data from the file, can use Scanner and specify the file - Foundational classes - Generic fundamental classes - Assume they exist at the beginning - Encapsulates data types w/ well-defined properties and actions - Highest focus for reuse - Examples: Date, Rectangle, and String classes [2.4 - Identifying Responsibilities] - We assign responsibilities to one class because there will be redundancy if we do not - Same method implemented - Responsibilities stay at one abstraction level - To initialize mail boxes: high level responsibility; we assign this responsibility to the mail box - Mid-level: the mailbox; this should not be dalt with - Processes key strokes (lower level) - Initialization of system (higher level) - Low level functions done by library functions - **When allocating responsibilities, we respect level of abstraction** - **Responsibility at high or low level?** - Look for **verbs** in problem description to discover responsibilities - Responsibilities must belong to exactly one class - If we add a message to a mailbox, is the message or mailbox responsible? - A responsibility will be translated to method(s) for the class - **Must be assigned to one class because there will be redundancy (same methods applied)** [2.5 - Relationships between Classes] - There are four relationships we will study when we create classes: **is-a, has-a, uses, and association** **[Is-a relationship (generalization)]** - When we have two entities: - One represents general concept and another represents a specific concept - Two diff mechanisms to represent is-a relationship: inheritance and through interfaces - Using inheritance: - If we have a person class and a student class, a person represents a general person and student represents a specific person ![](media/image10.png) - In Person class: bundle attributes and behaviors shared by all persons such as **name, age, getName, getAge** - Student class: instead of defining all general features in this class, we **extend** student with person, inheriting all general features. Student specific features and behaviors in student belong in this class, such as studentID, gpa, get studentID, getGPA (features that do not exist in Person class) - **Notation for inheritance:** - - When we create a student object, we get studentID + gpa, age, and name because a student comes w/ all behaviors of a person - This means that a **student IS a person because it comes with all attributes of a person along with attributes of a student** - **One thing to note: not all persons are a student, but a student is a person** - Using an interface: - Interfaces define the requirement to be the type; defines requirements without a body - Implementation specific to classes - If somebody wants to be a shape, it must implement: - draw(); (**interface defines requirement without a body; body of method is specific to classes that implement shape)** - contains(Point p); checks if point is boundary of the shape (specific to shape; not implemented in interface) - If anybody wants to be a shape, it must implement draw and contains method with a body - If we have a triangle class, it wants to be a shape. To do so, it must **implement** the shape interface - Triangle **must** implement void draw() with its body and boolean contains(Point P) with its body - Methods specific to triangle class; concrete methods ![](media/image12.png) - **A triangle IS A shape because it fulfills a requirement of a shape, but not all shapes can be a triangle (different shapes)** - Two interfaces can also have a is-a relationship - Moveable can extend Shape interface - **Requirements are inherited between interfaces** - Moveable defines move only. When moveable extends shape interface, the requirements of shape are inherited - Means three requirements are needed (draw, contains, move methods will need to be implemented) - A car that implements moveable has three methods to implement so its concrete (nothing abstract), the car must implement draw(), contains, and move with a body (its implementation) - **Moveable IS A shape, inheriting all requirements of shape. However, not all shapes are not moveable.** - **Car IS moveable as well; transitive relationship since moveable IS A shape. Therefore, car IS A shape.** - One important feature: it is implementation specific (**extends** keyword must be used when interfaces are using an is-a relationship) - If a designer identifies a is-a relationship through inheritance or interfaces, there will be a very specific way to implement a is-a relationship - The implementor has no choice but to implement the relationship in a specific way - If person and student is an is-a relationship, implementor uses **extends** keyword - If triangle implements shape interface, implementor uses **implements** keyword - **Is-a relationship is important because it supports code reusability** - Allows code to be used by different objects - Example: ![](media/image15.png) - Parameter b can take anything that IS-A bank account - If we define a method and the entrance to method is general (open to any bank account), method can be used by any bank account - If we build relationship between bank account, checking account, savings account, time-deposit account: - Saving account is a bank account - Checking account is a bank account - Time-deposit account is a saving account, which is a bank account - **Can write reusable program that takes any bank account** - For given method, can pass a bank account, savings account, and checking account for the method UML notation for generalization: ![](media/image17.png) **[Has-a relationship]** - One represents the whole and another represents a part - Composition: lifetime of part is exclusively owned by the whole - Whole is gone: part is gone - **Stronger has-a relationship** ![](media/image19.png) **Notation:** - Similar to a car and tire. A car has a tire, but their relationship is strong. If car is destroyed, tire is gone - Aggregation: special form of association; represents has-a or part-whole relationship. - **Implementation of composition and aggregation are the same** - Structural relationship that distinguishes the whole (aggregate class) from parts (component class) - Does **not** imply any relationship in lifetime of aggregate & components ![](media/image21.png) - A city has houses, but the relationship is weak. When city changes, houses are still there - **Has-a relationship has its PART implemented as an instance variable; it is PER object** - If we have multiple tires for example, can define a collection of tires (like an ArrayList) - **Program must be created so that tire variable is created inside the car so that a car has a tire** - **We need to create a private instance variable; has-a relationship ALWAYS implemented as instance variable** ![](media/image23.png) - **If we want a collection of Tires, we would have a private ArrayList of tires** - Filled and empty diamonds do not matter; diamonds should be located at the **WHOLE** side - **Has-a relationship is implementation-specific** - Specific way to write program; **part is the instance variable** - Applications can use has-a and is-a relationships - Classes can also have multiple relationships ![](media/image25.png) - Example: - Class vehicle and car class. A car is considered a vehicle; **CANNOT BE REPLACED WITH HAS-A. If a car is a vehicle, it IS a vehicle.** - A car can have an has-a relationship with tire - Corresponding program: - - When we create a new car, it will create a tires variable initialized as an arrayList in the heap - It will then initialize four tires in the heap - If there is an instance variable defined in the Vehicle class, it will be inherited and created in the heap - **An is-a and has-a relationship is different (not the same)** - **If given relationship is an is-a relationship, it cannot be has-a as well.** - We know that the part is always implemented as an instance variable of the whole - Question: are all instance variables of the whole representing the part? - Example: customer class defines many instance variables such as CID, name, CreditCard card ![](media/image27.png)**(should be String name)** - Answer: **No!** - Primitive types are attributes and are fundamental types in Java (like representing streams); they represent attributes most of the time - User defined attributes are not built in; **class needs to be explicitly defined for the application by the user** - Implication: **customer should be part of design. Credit card should be part of the solution and is a part of the customer class and CreditCard is our part** - **Essentially, not all instance variables are parts if the type of the instance variable is user defined.** **[Uses relationship]** - Dependency; when we have class C1 using class C2, it means that **class C1 depends on class C2.** - Dependency is very specific (not general) - In general sense, when A is B or A has B, A depends on B - When we say uses relationship, we do not say the general dependency - **In this case, when C1 uses C2, C1 uses C2 in place of parameter, local variable, or return type** - **C2 appears as a parameter, local variable, or return type** ![](media/image29.png) - Variables defined inside class, outside of method/constructor, variable is an instance variable - **To make something represent the part, make it an instance variable by defining it here so that whenever we create a whole, part is created inside object and leaves as long as whole leaves:** - Parameters, local variables, and return types are temporary variables - Lifetime will not leave along with object C1 - They will not leave along with object C1, they are created when methods are called and destroyed when the method returns - Memory allocated to parameter, local variable, or return type destroyed when method returns - **Therefore, C1 temporarily used C2 and C1 uses C2** - Temporary relationship is important because **is-a** and **has-a** relationships cannot be replaced when determined - Hence, **temporary relationship can be replaced by something else, or can be removed** - We want to replace/remove because if a design has a lot of dependencies, it gets hard to maintain the application - If C1 depends on C2, whenever C2 changes, C1 should reflect the changes - Changes on C2 seen by C1. wherever C1 goes, C2 goes with it - Having a lot of dependencies will hinder maintainability of program; minimize dependencies - **Such relationships (has-a, is-a) are hard to remove; meant to be there.** - **Uses relationship: if we can remove, remove it. If we can replace with a better relationship, we can replace it.** **Comparing the diagrams from the notes (for Voicemail System):** **Dependency Relationships** ![](media/image31.png) - MailSystem uses a Mailbox; temporary - Means MailSystem defines a method & parameter, local variable, return type is Mailbox - Whenever MailSystem uses Mailbox, has to call method & Mailbox given to MailSystem as a parameter **How it looks like in code:** **Aggregation Relationships** ![](media/image33.png) - Instead of uses relationship, MailSystem **HAS** a Mailbox - MailSystem has Mailbox as an instance variable - When we create MailSystem object, reference of Mailbox will be created as part of it - Mailbox reference leaves as long as MailSystem leaves - Whenever MailSystem wants to use Mailbox, it has a reference w/ no parameter passing - Whenever MailSystem uses Mailbox with parameter being passed, it comes with overhead - Whenever you call methods to receive a parameter and use it, some **activation record is created for the method and holds value of parameter, return type, local variable** - **Activation record pushed in stack and method can use parameter, local variable, return type** - **When method returns, activation record pops from stack & destroyed** - **Having a huge relationship and whenever we want to use MailBox, it has to call the method and creates overhead (uses relationship). On other hand, if we are using a has-a relationship, it comes with a reference; it leaves along with MailSystem if MailSystem has a MailBox** **How it looks like in code:** - **Since it is an instance variable, MailBox variable is created as part of MailSystem** - **When MailSystem wants to access MailSystem, it has a reference; no overhead.** - Can replace bad uses relationship with a better uses relationship ![](media/image35.png) - System.out is a variable from the library. If it uses print stream as a local variable this is bad design - Print stream is a local class that comes with methods that print to standard device - When it takes data, outputs data on standard output device (like console) - **Not all devices come with a standard output device, like small ATM systems** - If an application depends on standard output device, it cannot run on devices without it → **limitations on availability** - We can change it to a better uses relationship where it uses a String as a return type - Even though Java library is small, it always come with Strings - If message depends on String; when we run application, we write small helper code that takes string and displays it on the device; removes dependency on System and PrintStream classes Another example: - Registrar uses CourseSchedule, Course, Student in place of parameter **[Association]** - Represents a general binary relationship between classes - **Has-a, uses, is-a** are specific relationships. When we have is-a, use keyword **extends/implements**; has-a has part being instance variable of whole; uses means we have a B's parameter, local variable, return variable being used in A - When we start designing our solution, we are identifying classes and relationships - If we see that two classes/interfaces are somehow related, we know it - At the beginning, **we do not know how they are specifically related but want to document as association in the beginning** - Binary relationship: A and B are related and relationship is binary ![](media/image37.png) - A references B and B references A; do not know how specifically they are related. Do not know is-a, has-a, uses - When we open source code for A, B shows up. When we open B's source code, A shows up. - **We do not know if B appears in form of extends, implements, instance variable/parameter/local variable/return type** - At beginning of design, we say A references B, B references A - When we move closer to end, right before implementation, association must transform to specific relationships (is-a, has-a, uses) so **design documentation is clear, concrete, detailed enough** so implementor can rely on document to create program **[Multiplicity and role of association]** - Can specify multiplicity of A and role of A (along with B) - Multiplicity is a range of integers or just integers to specify how many objects associate with A (or B) - Many different ways to specify: - Range, just integer, or wild card (entire, nonnegative integer range) Example: ![](media/image39.png) - Roughly know course references student - Draw solid line: binary - Course multiplicity specified near course, student specified near student - Course can be associated with 17...35 - Student can take 3...6 courses - To interpret multiplicity: single instance of course is associated with at least 17 and at most 35 student objects - Single student object is associated w/ at least 3 courses and at most 6 courses One directional association link: - Explicit using arrow - Message queue associated w/ any \# of message, but message is not associated with message queue - **This implies that when we look at source code of message queue, message is mentioned (do not know specific relationship)** - **When we look up message class, messagequeue not mentioned** - Can specify role in plain English as long as it makes sense - **Goal of design: to identify classes and interfaces, identify their relationships and responsibilties** - **We use design tools like Noun/Verb to identify initial set of classes and interfaces (nouns) and verbs identify responsibilities** - **CRC (classes-responsibilties-collaboration) can be used to refine rough draft of classes and responsibilities** **[Use Cases]** - Always initiated by user & should describe interaction between user and system & at end of use case, goal should be achieved - Set of use cases are analysis tools; to analyze functional requirements - In case study, we develop VoiceMail system - Associated with main number - When user dials number, MailSystem maintains MailBoxes - Each MailBox associated w/ extension number - Multiple users can connect to MailSystem concurrently - Two users: public user and owner - Owner has more priviledges than public user - Owner can have a passcode and login - Owner can change passcode, greeting - Public user can leave message - Owner can listen to message, save message, delete message - Set of use cases are **an analysis tool; functional requirement analysis tool** - **10 use cases → 10 significant functions system supports** - **Use cases describe interaction between user and system; end should have goal achieved** - **Options take separate use cases** - **Options expressed as variations as well** - **We use use cases when all options are different functions. If coherent, use variations** - **Some options can be transformed into use cases while others can be expressed as variations that belong to the use case** - **If options are coherent and tightly coupled, they are considered variations & not separate use cases** - **Variations do not change goal of the use cases; they complete use case (covers scenarios use case does not cover)** ![](media/image41.png) [CRC] - Design tool; once CRC is done, we achieve goal of design (identifying classes/interfaces, responsibilties, relationships) - **C**lasses, **R**esponsibilties, **C**ollaborators - In design stage; identified requirements and conducted noun/verb analysis to find draft of classes/responsibilties - We refine classes responsibilities using CRC to finalize class responsibilities & identify collaborators - Collaborators help find relationships - CRC cards have 3 compartments ![](media/image43.png) - If we have 4 classes identified through noun analysis, we have 4 cards - If we have identified certain responsibilities through verb analysis & assigned them to classes, we list in the responsibilities section - **We finalize what classes remain in design & what responsibilities will be allocated to each entity & find collaborators** To identify collaborators for these classes: - Ask each responsibility this question: **can the class fulfill the responsibility by itself?** - **Yes: if mailbox can handle responsibility by itself, the responsibility does not need a collaborator** - **No: find collaborator from existing classes we identified** - **No classes that can handle it: add more classes that serve as collaborators for responsibility** - **If a collaborator is an existing library, do not need to mention (like ArrayList)** - **If we have user-defined storage that handles messages for example, we put it as our collaborator (like MessageQueue)** - For managing passcode & greeting, Mailbox can handle these by itself by using its own instance variable and methods - If we have a component intended to retrieve something (like a message from a MailSystem for the user), can put it in design and name it anything you like - Can add more classes based on understanding of system **How to refine CRC cards to finalize design** - By the time we are refining CRC cards, we have use cases - Each use case used to refine CRC card Example using Leave a Message use case ![](media/image45.png) - When you develop use case in first stage of requirement analysis, have **not identified classes yet** - When you mention system in use case, treat system as black box - Did not mention what component of system responds, but said mail system; treat mail system as black box - Reason: do not have any classes identified in first stage until we reach design stage - When using this use case to refine CRC cards, have idea what classes are involved - Do not have to write down; **interpret use case in detail in terms of classes identified** - How to interpret leave a message use case in terms of classes we identified; components of systems - We know what components of systems are involved - **If we look at \#1: check if Connection is listed as collaborator of Telephone. If it is not, add it to the CRC card.** - **Connection becomes collaborator of Telephone** - **Connection contacts MailSystem to find matching Mailbox** - **Check of Connection has MailSystem as a collaborator; if not add it** - **If we look at \#3: check if "manage greeting" is a responsibiliy for Mailbox. If not, add it. Then, check if MailBox is collaborator of Connection (if not, add it)** - **Repeat for rest of use case until goal is achieved** - **Discard any classes that are not used** - **To complete design, must identify relationships; collaborators are guidelines to find relationships** - If MailSystem collaborates with MailBox, start with **uses** relationship; see if we can replace with better relationship - Not other way around; **only certain that a MailSystem uses MailBox (same case for other CRC cards)** - Now, see if we can replace **uses** with **has-a** relationship - MailSystem will **have** references of **MailBox**; when MailSystem contacts MailBox, already has references w/o parameter passing [UML Diagrams] - Unified Modeling Language; design documentation tool - Use after design is done to document result of design - Focus on three major diagrams: class diagram, sequence diagram, state diagram - Must understand unique role of each diagram - **Class diagram: depicts is-a, has-a, uses, association** - Depicts static relationships among classes and interfaces ![](media/image33.png) - Each class depicted in rectangle & name for a simple class diagram - For comprehensive class diagram, rectangle more detailed - - Three compartments: **class name, instance variables, public methods** - **Mailbox defines two instance variables that are type MessageQueue** - **Two public methods; can add private methods too** - **Methods can have parameters inside parenthesis** - **Bracket after is the return type** - - Can specify accessibility - ![](media/image48.png) - No java keyword for package visibility; by default it will be package access (default accessibility) - **Sequence diagram: per-use case; if we have 10 use cases, we need 10 sequence diagrams** - Notion of time - Visualizes use-cases scenario - Think about what objects are involved & how they interact w/ each other to achieve goal of use case & visualize them - Objects communicate w/ one another in Java through method calls - Notion of time; time of sequence diagram flows from top to bottom - Should describe how object interacts w/ each other through method calls to achieve goal of use case (at bottom: goal is achieved) - **Find objects involved with use case & list at top of use case** - **All objects at top created before use case initiated & ready to be involved** ![](media/image50.png) - Any objects created in middle appear according to timing - **Underline objects to indicate they are objects** - If we know name of object, **can specify (often omitted bc they are not important)** - To depict method call interaction: - Every object comes with lifeline - Method call depicted as skinny bar; activation bar - Each activation bar depicts a method execution - As soon as method is called, it begins activation bar. End of method will be at end of bar - Length of bar is how long method is executed - Callee and caller are the method - Caller calls method of callee - **Method call can start in middle of activation bar; as soon as method is called, activation bar starts. Arrow can start of middle of activation bar bar of callee but should be at top of activation bar of callee** - Activation bar placed on lifeline of object that defines it ![](media/image53.png) - While method is active, another method of object called; overlap - Top of diagram indicates beginning of use case & time flows from top to bottom - At bottom of sequence diagram, use case ends & we acheive goal of use case at end of sequence diagram - Steps for sequence diagram: - Figure out what objects that were already created and ready to be involved in sequence diagram & draw them at the top - Objects already created & ready to be involved - Objects created in middle (like Message object in the case study) means it was not ready when use case was initiated - Objects in sequence diagram have a lifeline (dotted line); as long as object exists lifeline will exist - Telephone, connection, mailsystem, mailbox have a lifeline until sequence diagram finishes - Skinny bar is the activation bar; indicates method execution. Top is start of method and the bottom is end of method execution. Activation bar drawn @ lifeline of object that defines the method - Length of activation bar helps estimate length of method execution - Active method: method called but has not been returned - When we call a method: under the hood, corresponding activation record is created by the system and holds parameter value, local variable, where to return & pushed into system stack - While method is active after being called before being return, activation record is in system stack - When method is using parameter local variable, method can find values from activation record in system stack - When method returns, activation record popped and returns to designated position - During recursion, method is called → activation record stack. When returned, activation record stack popped - Very common while method of object that is still active will not return yet; can have another method be called - Methods calls should have caller and callee ![](media/image55.png) - Telephone's method is the caller, connection's method is the callee - Telephone calls dial method. When telephone calls callee, arrow should be at the top of activation bar of connection - Understanding the sequence diagram: - Use case (leave a message) initiated by user when user enters extension - Dial method of Connection called in middle of execution; by the time dial comes w/ extension, Connection calls findMailbox to find corresponding Mailbox for the extension; method retruns mailbox information (return arrow can be omitted) - With mailbox reference, Connection can call getGreeting method to get and display the greeting to the user - Then, speaking returns and dial method ends - When user speaks message, will call record method of Connection to record message & returns - When user hangs up, calls hangUp method and calls create method and creates the Message - After Message is created, hangUp method of Mailbox calls addMessage method then returns, thenhangup method returns - Control logic in sequence diagram can be controlled by using guards - \[pastDueBalance = 0\] is the guard; checks if condition is true - If pastDueBalance = 0, then it will be true. Otherwise, it will not add a student - Large rectangle compartment in sequence diagram labelled with alternative (alt) and to describe a condition to show the interactions ![](media/image57.png) - Option is a selection w/o alternative; if true, entire action done. Otherwise, no alternative done - Loop: repetition fo interactions when condition is true ![](media/image59.png) - **State diagram: depicts state changes of an object throughout program execution** - Visualize how state of object we are targeting changes throughout program execution - **Do not need to draw state diagram for every object; tedious** - **Decide what objects need a state diagram** - Find one or two significant objects that need a state diagram - Objects that take input and frequently change state due to user input deserve to have a state diagram - Connection is an example (from our case study) - State depicted in rectangle w/ round corner - Arrows describe the state change - Can describe event that triggers state change on top of arrow [Javadoc] - Tool comes with Java library - Using Javadoc comments can describe API of program we are developing; we are responsible for writing Javadoc comments - We write Javadoc comments in source code - Difference between ordinary comments and Javadoc comments ![](media/image61.png) - Purpose of general comments: to explain/support readability - When somebody reads your source code, helps explain meaning behind your code - **NOT RECOMMENDED TO COMMENT UNNECESSARILY; HINDERS READABILITY** - **Better to use meaningful variables so that without any comment, it is obvious to understand meaning of your code** - Javadoc comments have a different syntax - Describes public interface of your program - **If you specify a Javadoc comment, comments will go with source code and there is a tool called Javadoc that extracts ALL javadoc programs and builds tree structure of API for your program** - **VERY IMPORTANT TO DOCUMENT JAVADOC COMMENTS PROPERLY** - Users do not have access to source code; rely on API you provide users with to know roles of classes, what kinds of methods/constructors defined, return values, parameters to pass - General comments do not appear in the API; part of source code to help readers of source code understand your code ![](media/image63.png) - Details of Javadoc comments: - File Javadoc is per file, regardless of how many classes the file contains - File Javadoc should show one line of what kind of information the file contains. - At **beginning of the class,** class Javadoc will have **one line explaining the Javadoc** - Every cosntructor & public method should have Javadoc comment as well - Except for private constructors, imagine whatever user of class want to use, should have Javadoc comment so they appear on API - One line of explanation & @/param if constructor takes a method - Precondition and postcondition are contracts between method developer and method caller - As developer: specify what conditions must be true when method is called (precondition) - Caller is responsible to satisfy precondition - If developer successfully specifies precondition & caller violates, developer not responsible for malfunction - If caller satisfies precondition, developer successful execution of method - **Developer writes the precondition; caller is responsible for satisfying the precondition** - **If caller calls method w/ correct precondition → precondition satisfied** - **Postcondition guaranteed; what method will do after method is done** - **Precondition is the correct value of the parameter** - Accessors do not take parameters; no @/param but returns a value; @/return tag used - Dont need precondition & @/param because there is no return value - Return is necessary because accessors return a value - Postcondition redundant with a return; do not need to describe a postcondition - @/throws enforces a precondition as well - Throws an exception if precondition not satisfied - **Static variable is variable that is created per class** - **Per class means its created once for all when class A is loaded then shared by all objects** - **Therefore, static variables cannot serve as the part** - **Instance variables are per object** - **Since its per object, whenever you create an object, instance variable is part of the object** [Chapter 4: Interfaces and Polymorphism] ==================================================== - All methods declared in a interface end with a semicolon - No body of method provided; only specifies required method - Methods are defined as abstract in interfaces - Interface defines requirements of abstract data type (ADT) - A type is a bundle of values and operations the system recognizes - System perceives these types - Example: int means bundle of integer values (all integer values and integer operations) - If we say int, system perceives int - Int i → type declares i can take on values of integer type (int i = 10 works) and that we can apply integer operations to i - If we assign non-integer values to i, the system will not compile it - Non integer operations will not compile it as well - **8 built in types: byte, short, int, long, float, double, char, boolean** - **Do not need class or interface for them** - **ADT: type that needs class or interface** - Example: ArrayList is not built in; abstract. Need public class ArrayList to use type - **Interface defines requirement of ADT (abstract data type)** - Interface at top of hierarchy to define ADT - Shape interface defines requirements to be a shape - boolean contains (Point p); - Void draw(); - If shape imposes two requirements, anything underneath should fulfill the requirement (like Triangle; must fulfill requirement) ![](media/image65.png) - Main entities of OOP: Interface, Concrete class, Abstract Class - **Role of concrete class** - **Concrete class means everything is completed; nothing abstract** - **Implication: concrete class is only entity we can instantiate** - **It means it is the only entity we can get an object** - **That means the role of a concrete class is to implement abstract data types (to get object out of it)** [Features of Interfaces] - Can be from library (like Icon) or can define your own - Defines types; if you have Icon interface, can define type - **What are the values we can assign to Icon variable?** - Instance of class that implements Icon is the value of Icon variable ![](media/image67.png) - **Cannot instantiate a new Icon because we cannot instantiate interfaces** - There should be a public class that claims to be an Icon (implements Icon interface) - MarsIcon has to implement the methods from Icon; MarsIcon becomes concrete - Can call methods i.paintIcon(); because it is an operation that comes with Icon - Interfaces can also extend another interface - Building is-a relationship using extend ![](media/image69.png) - Movable interface **is** an icon - Movable becomes an icon by inheriting requirements of Icon - Movable defines explicit requirements; means Movable has 4 methods - If a class implements Movable, **must** implement 4 methods - What this means: if we have an Icon variable, we can assign Car. We can also assign Car to a Movable variable. - **Interfaces are not classes; they cannot have instance variables** - Interfaces cannot be instantiated (cannot create objects); instance variables are variables per object so we cannot instantate instance variables in an interface - If we do have instance variables in an interface, it becomes public static final variable - Not per object, per class - Once we initialize the variable, cannot change th value - **All methods defined in interface are considered public abstract** - A class can also implement as many interfaces as it likes (Java specific) - Can build multiple is-a relationships through interfaces in Java - Recall: two ways to express is-a relationship: inheritance and through interface - One entity can have multiple is-a relationship ![](media/image71.png) - Common to have multiple is-a relationship; but we cannot have multiple inheritances **THIS IS NOT ALLOWED** - **Reason is due to ambiguity problem** - In Java, subclass cannot selectively inherit members from superclasses - If class extends superclass, **everything is inherited except the constructor** - (if we were allowed to do this) If there are common members in two of the classes, the two members are inherited w/o choice and they conflict. StudentWorker is ambiguous because we do not know which one to use ![](media/image73.png) - We can have multiple implementations, however - If we have Student interface and Employee interface with StudentWorker class & it implements the interfaces, there is no ambiguity problem - No member (variable, method) because the interfaces define requirements - StudentWorker defines requirements of student and employee to be student and employee - **If student and employee define common requirement,** then studentworker implements union of student and employee & puts them in studentworker - Multiple is-a relation implies that **we can create studentworker** and pass it (same as Employee) [How to Use an Interface?] - Three methods from Icon interface with **exact** method signature and same visibility - **CANNOT RESTRICT VISIBILITY; CANNOT BE LESS** - If interface defines it public, cannot make it private (or we get an error) - Same return type or if ADT, same ADT or covariant type (subclass of the type) - **Method signature: method name, type, and number of parameters** - **Method header: visibility and return type are part of method header** - If MarsIcon wants to be concrete, there should be **no** abstract methods - There are also all methods complete with its body - **For given interface, can be many concrete icons & all have the same method w/ same method signature** - Allows Java to find the method - **All concrete Icons will have same set of methods w/ same signature BUT DIFFERENT BODY** - **Every concrete class that implements Icon interface** will have three required methods w/ same signature w/ different body - Question: can MarsIcon define own methods not required by Icon? - Yes! MarsIcon is its own class and can define methods defined by its own class [Benefits of Using Interfaces] - We use interfaces to build an **is-a** relationship - We build an **is-a** relationship for reusability ![](media/image75.png) - JOptionPane displays small messages & images on the screen - ShowMessageDialog is an example of a reusable program - Many parameters; we only focus on the last parameter **Icon icon** - **Is-a relationship is a prerequisite for reusable programs** - Once is-a relationship is a prerequisite... - Entrance to program should be general enough - **Reusable program should be used by many Icon objects** - Should be able to pass MarsIcon, ImageIcon, etc. - **If MarsIcon is the parameter instead, it will not work because it will only take something that is a MarsIcon** - When you describe logic of method, you use operations that exist in any Icon - To find common methods shared by any Icon, it will be in Icon interface - It will list all requirements that must be satisfied that is an Icon - Guarantees that if someone is an Icon, we get three operations - Logic is described by common operations of Icon type - Common operation: all operations shared/required by any Icon - If we pass MarsIcon, it should have all the requirements to execute the method - **If we want to host a party and invite many people....** - Need to have relationships w/ people invited - If we invite people and any Icon can be invited, entrance should be general enough - When party is hosted and we prepare the food, anybody can enjoy - Not only part of crowd enjoys; food is **general** - **Icon interface provides general food** - Can prepare food for everyone as long as they are icon - **Cannot have icon.marsIconSpecific(); method only exists in MarsIcon** - If it passes ImageIcon, it is annoying (cannot have) [Polymorphism, what Compiler does] - Kicks in at runtime - Compiler only concerned about type; does not care about what happens at run time (VM is responsible) - Compiler checks for type compatibility - Checks if what is written is compatible w/ notion of type - If you are the compiler and we try and compile public static void showMessageDialog(\...) - Checks type of variable parameter - Compiler remembers type of variable icon is an icon - Compiler also checks for syntax at run time - **Compiler checks if value we are using on Icon & operations are type compatible with Icon type** - Checks if operations are compatible with Icon type - Compiler references Icon interface & checks if the operations are bundled w/ Icon interface. If it is, will compile - **If there is a line that is MarsIcon specific, will refuse to compile. MarsIcon is not bundled w/ Icon type (remove and recompile)** - **Role of compiler: checks if program is general enough to serve any Icon** - To see how program runs at runtime, consider method call - In main method: - When we call the method, we need to pass a parameter. We pass an object **that is** **an Icon** - In this case, we pass a MarsIcon object - MarsIcon object passed to Icon and the Icon parameter references MarsIcon object & executes the body - **When VM executes the body, will call method** - Icon variable references MarsIcon object and VM has to call paintIcon - VM has to make decision; every Icon has paintIcon method even w/ same method signature - Compiler cannot make decision which one we want to call at compilation time - According to method call, there are many methods with same signature - Binding should be delayed at run-time - VM responsible for making decision (binding); which one (object) to call - Compiler does not know which object Icon will reference; at compilation time, compiler cannot decide which one to call by type because everybody has method with same method signature ![](media/image77.png) - **At runtime, VM has more information about icon variable (which object Icon variable references)** - **At runtime: if Icon references MarsIcon object, will call paintIcon for MarsIcon object** - **Early binding:** decision made at compilation time - **Late binding:** decision done at run time - **Polymorphism kicks in at runtime; VM checks which method to run based on the object type** - Depending on the object being referenced, it will call the method based on the object [Overloaded Method] - When we have a class... - If it has two or more methods with the same name, the number of parameters and/or the type of parameter should be different ![](media/image79.png) - Overwritten method is when a method is defined in superclass and we want to enhance it in the subclass - Requirement: method signature must be the same & visibility must be the same (cannot be weakened) and the return type should be the same or covariant (subtype of inherited method) - Method signature: way for Java to recognize a method - Method name and parameter list will constitute a method signature - Parameter list is the number, type, and order of the method - **(Java specific) Method signature does not include return type, access modifiers (public, private...), and throws clause** - Early binding: decision made at compilation time - Compile-time binding or static dispatch - Compiler in charge of runtime; makes decision based on reference type (type of variable) - Check the type of a variable and see if method exists in that type - Late binding: decision made at runtime - Runtime binding or dynamic dispatch - If we have a bank account for example, a decision can be made based on reference type early ![](media/image81.png) - Compiler checks if reference type defines deposit. If it does, compile. Otherwise, compiler makes a decision and decision will go on to runtime. - In other words, when reference type and object type are different OR object type is not known, the decision (which method to call) should be done at runtime - Method to call is based off the actual type of the object at runtime [Example of early-binding (overloaded method)] - In the same class, a method is defined with the same name - Method signatures should be different so that they are valid methods - To make different method signature: different number of parameters, different type of parameter, different order of parameter - Return type does not affect method signature; can be same or different - number/type/order of parameters different in example - public String (int add) would not be considered a method signature; would mean we have a method signature and we can't have this method - Since they all have different method signatures, the compiler can determine which method to call [Example of late-binding through method overriding and implementing methods of an interface] ![](media/image83.png) - Method overriding: if a function in a superclass is not good, we override it in the subclass to have a better implementation - @/Override overrides a method in an interface - Once we override, inherited method will not exist - For interfaces, if we have a class and the interface imposes a requirement m - If a class implements m with method body, these rules are common on how to override and implement method - Common because method signature **needs** to be the same - Makes it so that the inherited method is completely gone and overriden by overriden method - When we implement method from interface, method signature must be the same - Visibility must be the same; cannot weaken it (cannot go from public to private) - Return type must be the same. However, can be covariant (like a more specific type) - Overridden method may return savings account instead of bank account ![](media/image85.png) - Inherited method is gone for savings account object - Only overriden method available - Looking at method calls: - Reference type and object type are the same; compiler can make a decision on what to print - For the third method, they are different (general and specific type). - Cannot make decision on reference type - Decision delayed until runtime; making decision based on object type - Looking at reference type: object type is not specified - Decision delayed until runtime - Decision made by VM at runtime and the object type will determine which method to call - If we call reusableMethod with savings account object, savings account M will be called - Animal interface defines makeSound as requirement of Animal type - When we have general variable Animal and object type is specific, compiler cannot make decision about myAnimal1.makeSound() - Cannot make decision because myAnimal1 may reference a different object that is more specific - At runtime, VM calls makeSound of dog based on object type - **Which one to call is determined by object method is activated on** [Default Methods] ![](media/image87.png) - Mark method as default & provide method with a body - Interface at top of design hierarchy when defining requirement of ADT - For shape, defines requirements in form of abstract method - For the classes that want to be a shape, will need to implement all abstract methods - For them to be concrete classes, they need to implement the abstract methods with body to create objects A drawing of a diagram Description automatically generated - Default methods are useful when: - Making it easier to implement future methods - Prevents user from adding unnecessary methods from an interface - When adding new requirement to interface or new requirements to interface heavily used, provide default body (concrete body) so that classes that classes that implement the interface can inherit the default method - Classes will have an option; inherited method or some classes may override it - **Essentially, introduced as a way to add new requirements and eliminate burden on classes that implement interfaces by providing a concrete body** - **If a class chose not to override a default method, method will be inherited to the class anyways (will be available for object of the class)** - Without default method, if we add it like an abstract method, EVERY class should have the update - Gives classes an option (override or do not do anything) - Ambiguity problem: if a class tries to extend multiple classes, will not be allowed - Rule of thumb: when subclass extends superclass, subclass cannot selectively inherit members - Everything is inherited except constructors - If some members are the same, Java will not know which method the subclass will use - To eliminate ambiguity problem, does not allow multiple inheritances - Multiple interfaces are allowed however - A class can implement multiple interfaces; allows multiple is-a relationships - However, if there are default methods with the same method signature, there will be a conflict because default methods are inherited [Dealing with ambiguity problem] ![A diagram of a computer code Description automatically generated with medium confidence](media/image89.png) - When we have a superclass and interface and a class inherits the superclass and implements the interface where one is a method and the other is a default method with the same signature: - Superclass' method takes priority over the default method A group of black and white drawings Description automatically generated with medium confidence Two interfaces, with one defining default method and the other defining requirement: - Method must be explicitly showing up in class & clear body to tell Java the exact function to resolve ambiguity problem Two interfaces that both define a default method: - Class must explicitly define method with a body to resolve ambiguity problem Example of second case: ![A computer program with text Description automatically generated with medium confidence](media/image91.png) A computer code with text Description automatically generated [Comparable Interface Type] ![A close up of a text Description automatically generated](media/image93.png) A black text on a white background Description automatically generated - compareTo method used when comparing two different objects - When we pass type argument, it replaces all instances of \ (conceptually) - If anyone wants to be Comparable, has to fulfill compareTo method and takes one parameter of type T and returns an integer - If method is called: - \< 0 if object1 comes before object2 - 0 if equal - \> 0 if object2 comes after object1 - **Does not promise which negative number** - cannot do if(ob1.compareTo(ob2) == -1); must do \< 0 , 0, or \> 0 - Means we can pass any list with type T - If there are any restrictions to impose T, can describe in \ - **Note: cannot pass list of any element; elements should be comparable first. Otherwise, cannot sort random elements** - **Impose restriction; cannot take any T** - **T must be comparable; done by saying \** - **This extend is keyword to mean IT HAS to be** - **Example: public static \ void Sort (List\ list)** - **Must pass list of comparable to use sort** - **Can take any list with elements that is comparable** - **When writing body, use general operation that is used by Comparable** - When building is-a relationship using comparable, one has to provide type argument - Country is comparable & country class specifies the type argument as Country - All occurrences of T are replaces by Country conceptually - **Requirement is int compareTo(Country)** - Takes country as a parameter and comparison metric is the area - When calling this method, C1's area is compared to C2 - According to API, will return a positive or negative number - **compareTo compares this parameter and other parameter** - **This** (Country) should define compareTo ![A close-up of a drawing Description automatically generated](media/image98.png) - With comparable approach that requires compareTo, the **this** object must carry compareTo - Object to be compared that carries compareTo should decide which comparison metric (like area, name) - If one wants to change comparison metric, source code needs to be changes (like for name) - Another example: String library is comparable - Implies we can write reusable programs - Sort from Collections class is also a reusable program - Reusable programs depend on Comparable only and **String and Country and decoupled from sort reusable program** - This is how the sort method is reusable by any Comparable - If sort depends on Strings, it cannot be used by Country - A whiteboard with black text Description automatically generatedRestrictions on T need to be imposed - Any list where element type is T can be passed (Linked List, Array List) - **Sort cannot arrange elements in order unless T is comparable; cannot take any element** - T **has to be comparable** - **Use extends keyword to express this restriction; T extends Comparable\** - This doesn't inherit Comparable; this expressed **has to be (has to be Comparable)** - Sort method takes any list with element T - Sort depends on Comparable - Reminder for reusable programs: - We have a is-a relationship - Requirement for reusable program is that it should be general enough - Should not be list of String or Country; list of Comparable - When describing logic of method, use common operations available for any comparable (In this case, compareTo) ![A close-up of a math equation Description automatically generated](media/image101.png) - For the sort method, it uses a loop - It takes two elements from the list and determines their order - Method repeated until elements are sorted - These elements are type T - When they are compared, can use operation available by Comparable - This is guaranteed that first is comparable, along with second - **This makes the instruction general and makes the sort method reusable** - Result is integer as well - Compiler takes responsibility in compilation time and compiles - Compiler remembers that T is a comparable type and applies it to check type comparability - Then, compiler checks for type T when checking first.compareTo(second) - This works because both objects are Comparable - Compiler cannot make decision on which compare to call - **This** comparable type has is based on only type T everyone has compareTo with the same method signature so compiler cannot make an early decision - Method to call postponed until runtime - VM makes call based on object type based on polymorphism - If we call sort method with an ArrayList of Country - Country comes with name and area - According to compareTo method of country, they are compared by area - Parameter list references the ArrayList of Country - When we say list.get, it gets US with area of 100 first and second will be Thailand of area of 10, they are compared to after - compareTo finds out that this.area \> other.area and returns +1 - **Polymorphism kicks in during runtime because we have the same signatures** - **VM calls compareTo of Country object according to polymorphism** - If we call it with a different ArrayList - This list now references array list of Strings - When you get list.get(i), A gets returned - VM calls compareTo of String according to polymorphism - compareTo of String of library compares strings based on lexicographical order; returns -1 since A comes before B in lexicographical order - **Limitations of comparable:** - Rooted in the fact that the object that is being compared has to carry compareTo. - Hence, when you make an object comparable, need to access source code of class and hard code an implementation of compareTo and Comparable - This implies that we do not have access the source code of the object to be implemented and the object being compared, cannot make the object Comparable - Example: Rectangle is not Comparable and we cannot access this class no way to order Rectangles using Comparable approach - Even if we have access to the source code (like own Country class), whenever we want to change the Comparison metric, source code needs to be changed and recompiled and integrate to application again - There are cases where we want to change Comparison metrics - Example: providing way for Customers to compare hotel rooms by price, location etc. Therefore, various comparison metrics should be implemented. However, Comparable does not allow this [4.4 -- The Comparator Interface Type] A close up of black text Description automatically generated - Requires only one method - **Compare does not compare an explicit parameter** - **This (parameter; object to be compared) does not have to carry logic to compare object** - It takes two explicit parameters and these parameters will be compared - If we are using Comparator approach, class Country will not implement Comparable. As an ordinary class, it defines set of instance variables, constructors, methods. - Can write a small program that claims to be a Comparator - **This is called a function object**, this class does not need instance variables because the only use of the object is to compare two objects. - **Writing small Comparator class that compares two objects** - **Hard code comparison metric as part of Comparator class; separate from the main class like Country** - Can use object comparator by name when we want to compare two objects by name - Can write as many Comparators as we need based on needs of the application ![](media/image104.png) - Can write as **many Comparators as we would like one for each comparison metric** - **Our own classes so we have access to them** - **Very small; can write as many depending on application** A diagram of a comparator Description automatically generated - Comparator allows us to build is-a relationships once we have an interface - Country does not need to worry about how to compare Country, comparison logic is decoupled from Country and are implemented in those two function objects - Sort method only depends on Comparator interface and is decoupled from a specific Comparator - This allows the sort method be reused by different Comparators - **Hence, sort method depends on Comparator so we can pass Comparator by name and area** - When we write logic of sort, we use common logic by any Comparator (compare) - **Since we are using Comparator approach, Country is free from Comparison logic** - **This forms is-a relationship between Comparator and specific Comparators** - **This allows us to write reusable program based in terms of Comparator** - **This makes the reusable object serve different objects (name, area) polymorphism kicks in** - ![A diagram of a diagram Description automatically generated](media/image106.png)Since we have an is-a relationship, a sort method can be implemented that only depends on Comparator - Entrance to our program is general as well - A white board with black text Description automatically generatedParameter takes List\ list - No restriction, we want to take any element (does not have to be Comparable) - Even if the object is not Comparable, we should be able to compare as long as we pass Comparator that knows how to compare T - **T is free from Comparable; sort takes any List of type T as long as we pass a Comparator that compares T** - Sort method is different; sort methods are overloaded - Loop runs until every element is sorted - We get first element of type T and a second element of type T - To compare the first and second, we cannot do **first.compareTo(second)** because there is no guarantee that T is comparable - We can call call c.compare(first, second) - Pass two explicit parameters - Comparator as a compare method - Result is an integer - When the compiler compiles the program, it takes all the information - Remembers type of C is comparator - Checks if every Comparator comes with compare (it does program compiles) ![A whiteboard with writing on it Description automatically generated](media/image109.png) [ ] - At runtime: - If we have an array list of countries, we also need to create a comparator object (like ComparatorByName) - When we call sort, this.list references array list of countries and Comparator references the ComparatorByName program runs - According to polymorphism, it calls the compare method by name - Compare method of ComparatorByName is called; compares countries by name - Returns -1 - Problems of Comparable solved - Comparatorbyname and area is available for us - Do not need access to source code of Country; can compare as long we write the Comparator methods - Can write as many Comparators as needed depending on Comparison metrics [4.5 -- Anonymous Classes] - Anonymous classes introduces lambda expressions - Anonymous classes help understand lambda expressions - **Anonymous object:** - When an object is created, object is created in main memory heap - **new** returns the memory reference of the object - when its created, it does not have a name - **If we want to access the object multiple times, we need to name it** - For anonymous classes, if we want to access the class multiple times in program execution, we name it - In application, can access the class many times - If the application does not need to access it multiple times, we create object once and pass object to somebody else and the rest of the program doesn't need to access the class - **Means we can use anonymous classes write class without name** A close-up of a white background Description automatically generated - Anonymous class declaration always starts with new - Class doesn't have a name, so we instantiate it at the same time we define it - With name, can have two different steps - Can define the class and instantiate it with the name - Since anonymous class doesn't have a name, we define it at the same time - Because there is no class header, if there are any is-a relationships, we specify it after **new** - Class body: whatever we write in class with name, we write it - New statement should be executed; add semicolon to make it an instruction - **This defines a class without a name and instantiates it** - When new returns reference of the object, **comp** takes it - **Comp is name of object of anonymous object so we can use comp throughout the project allows us to pass comp to the sort method** - **Collections.sort(countries, comp)** - Factory method: - Method that returns specific object - Whenever you call this method as a factor of comparator, it returns a comparator object - **In principle, we instantiate it once and never use the class** - This is why we declare without name - If we want to use anonymous class and want to instantiate it over again, we use factory methods - **Return comes with anonymous class declaration** - **Whenever we call the factory method, anonymous class is defined and instantiated and returned** - If we want to have many objects by calling this method, we use factory methods - We call class.method name (in this case, the method returns, defines, and instantiates object and returns a comparator object) - Passed to sort method - Same idea for countries2 as well - **Factory methods should not be void! It should return an object (not a primitive type)** - We rely on graphic library - We use AWT and Swing - AWT is a primitive graphic library; has limitations - Abstract Window Toolkit - All classes for AWT are arranged in packages (java.awt) - Swing - Class name beings with J for Java Swing - In swing library, classes are arranged in package javax.swing - Name of classes start with "J" like JFrame - Limitation of AWT: rooted in way its developed; peer-based approach - Swing overcomes them through a non peer-based approach - Peer-based approach means the platform the application is running on - Each peer/platform comes with own graphic library - **Peer-based approach means that the AWT relies on the graphic library of the platform** - If we have an application that wants to display a box, when program is written using Java AWT and it is run: AWT library grabs box object from graphic library of platform and displays it - Therefore, Java AWT library relies on graphic library of the platform to paint, draw, and display components - Drawbacks of Java AWT: - When you have a GUI program, this program depends on where we are running the program - Users have different look and feel; application uses different graphical component based on the platform no consistency displaying graphic component - Bugs and errors from library can vary depending on which platform we are developing the application - Some platforms come with a very limited graphic library - Ability to display graphic components limited on platform - Swing is non-peer based approach - Only function Swing borrows from the graphic library of the platform is the ability to paint, draw, and open paper to draw - Everything else is programmed using Swing library - Gives consistent look and feel - Name of classes will start with the letter "J" in Swing library - Inheritance hierarchy for JPanel and Jframe - As we go up, concepts get general and functionality get more primitive - As we go down, concepts get specific and implementation is more specific - **Object** is mother of all existing Java world - **If we have a class** and it does not extend anything explicitly, it automatically extends Object; Objects created are directly underneath it representing a general object - Component is an object, but not all objects are a component - Component has more specific features than a general object - **Features of component:** most general object we can display on a screen - Whatever we can display, will be underneath Component - Container is a component; can display containers. - More specific feature: container can have multiple components as a container and display them together (like buttons) - Window is a container, which is a component - Allows us to display a window on the screen - As a container, can add multiple components to the window - **Additional feature:** All classes underneath window are like paper to display individual components - If we want to display anything, must have Window first then display components in the Window - Frame is a window; container + component - Frame can be used as paper and add multiple components to frame - Additional feature: Frame comes with title and border line - Jframe can be displayed and is component to frame - Can add multiple components because this a frame - Can be used as a paper because it's a window and comes with title and borderline because it's a frame - Additional feature: if we want to display component from Swing library, we **must** use Jframe - Jcomponent is a container component - Additional feature: most general Swing component - Anything under Jcomponent is a component from the Swing library - Header for Jcomponent - Header defined as abstract; Jcomponent defines concrete methods - At the same time, it defines abstract method without body - Class that uses concrete and abstract methods must be defined as abstract using Java keyword abstract; otherwise program doesn't compile - In OOP design, we have abstract classes - Some methods have concrete body so that subclasses of class can inherit and use it - Overriding is optional - Having abstract method in abstract class means that it leaves implementation of method up to subclass - Abstract class defines class as abstract without body - Concrete methods inherited to subclasses; subclasses use them - Abstract methods are inherited as requirement to subclass to implement - Special feature of Jcomponent: - Abstract class abstract entity - If we have an abstract entity, we can't get an object out of it - Purpose of abstract class is in the hierarchy of the design, the abstract class comes with concrete methods subclass must inherit & abstract methods that subclasses can inherit - Jpanel comes underneath Jcomponent and is a concrete class - Hence, can have concrete object of Jpanel - Being concrete is specific feature of Jpanel compared to Jcomponent - Jpanel is a Jcomponent which is a container which is a component - If we write our own class and its under Jpanel (it extends Jpanel), class becomes Jcomponent because is-a relationship is transitive - Example of GUI program (simple) - Presents two buttons and has one text field that displays "Click a button" - Buttons are labeled "Say Hello" and "Say Goodbye" - **Always prepare a paper when writing a GUI program; in this case it's the JFrame** - Jframe will have many mutators, such as setting the dimensions of the frame - It will be 300x200 in this case - Next, create Jcomponent of choice - Hello button and Goodbye button are the same so hello button is used in example - Hello button is a Jcomponent; Jbutton is a Jcomponent (Jbutton is specific Jcomponen) - Next, create JtextField (another Jcomponent) - Using constructor, can set length of text field and set initial text with a mutator method - **Creating Jcomponent does not mean we see them automatically** - We create many Jcomponents in a GUI program - To see the Jcomponent, we must add them to the Frame (Frame is a window, which is a container) - Every container comes with add method; so we add the buttons - Jframe will have a reference of Jbutton and we add Jtextfield, Jframe will have reference of Jtextfield - Will be in heap of memory; cannot see them yet however - **Need to set the Frame as visible** - **Virtual machine visualizes Jframe and examines all components added to Jframe and visualizes them** - We created 300x200 Jframe and created Jcomponents extra space - Frame.pack minimizes the frame size to accomodate components we created - Frame.setLayout - Jframes (and containers) come with setLayout method - **If a component holds multiple Jcomponents, there should be a way to lay them out** - Swing library provides various layout manager objects - Set layout of current container using layout manager object provides you with - Example: flow layout arranges components left to right. If it runs out of space, it goes to the next line - There are other layout types (grid, boarder) as well - Grid: each component that is added is added to its own grid - Boarder: components are added to north, south, west, east, or center of frame - setDefaultCloseOperation(Jframe.EXIT\_ON\_CLOSE) - When you run a program, program execution starts from main - main being executed means that OS will spawn a main thread that is in charge of executing the program - Executes each line - Main thread terminates when main method is done, but we still see Jcomponent and Jframe on the screen screen still - This means that graphic program involves multiple threads - Even though main thread is terminated, another thread is spawned containing Jframe object and Jbuttons - If setDefaultCloseOperation(Jframe.EXIT\_ON\_CLOSE) is set, if we close the Jframe all the threads will be killed along with the program - No threads survive OS prompt back - If we don't have this, there are still threads holding on the OS - When developing own application, want to have own Jframe and Jcomponent with customized look and feel programmed by you - We create user-defined Jcomponents as a result ![](media/image118.png) - HelloFrame is a user-defined Jframe that is user-defined - To make the class as a Jframe, make it an is-a relationship with Jframe (extend the class) - Everything is inherited from Jframe to HelloFrame; HelloFrame becomes a Jframe - Constructor calls this.setTitle and this.setSize and defines user-defined Jcomponent then calls this.add(panel) - **This in this context is the object we just created (the HelloFrame)** - helloFrame does not define setTitle and add method but are used as if HelloFrame defines them - they are inherited from Jframe; available for HelloFrame - object's title is hello, object's dimension is 300x200, and whenever we create the object, it always comes with HelloFrame because constructor added panel to the frame - setVisible will visualize the HelloFrame and in return, the HelloPanel - HelloPanel is a user-defined Jcomponent as well - Jcomponent is most general Swing component (reminder) - Class should be underneath Jcomponent in a design hierarchy and should be build a is-a relationship - If the class directly extends Jcomponent, we need to use Jpanel because Jcomponent is abstract (and Jpanel is a concrete class) - Class becomes Jcomponent because of the transitive relationship - Typically, class extends Jpanel which extends Jcomponent - **paintComponent defined as concrete method in Jcomponent** - **this implies that every Jcomponent has a paint component (due to inheritance)** - paint component of jcomponent describes look & feel of Jpanel - Jbutton also has paintComponent; describes look & feel - **Hence, paintComponent describes the look and feel of the component** - **When car is visualized, (component), car is displayed)** - **Jcomponent class defines paintComponent w/o much function** - **Must override because because inherited look and feel from jcomponent is useless (too primitive)** ![A diagram of a variety of text Description automatically generated with medium confidence](media/image120.png) - To override, we use the exact method signature (name and number, parameter type and order) - Hence, method signature is given because Jcomponent defines as public; must make it public and void with graphic given - **When overriding method, call inherited function, fulfill the inherited function (primitive function) and describe specific function** - When displayed, look will be "Hello" - **Do not call paintComponent direcly, VM calls it** - When you have Jframe and add Jcomponent (like hello) we see this: A black and white drawing of a rectangular object Description automatically generated - Every Jcomponent comes with paintComponent; feature of every Jcomponent - If we call frame.setVisible, it will visualize the Jframe and paintComponent will be called by the VM and will be painted - Several cases where VM calls paint component - Running program for first time (when program reaches frame.setVisible, VM calls Jcomponent.paintComponent) - Resizing; Jcomponent is repainted (it will call paint component of component again) - Overlapping: if we have one Jframe displayed and it has some component displayed - If we create another Jframe that is overlapped with the previous Jframe - When we close one of the Jframes, the overlapped part has no way to partially paint something - Does not store partial information underneath top frame - When we close it, entire Jframe should be repainted calls paintComponent method - **Key point: we program paint component but virtual machine calls the method** - **Hence, we do not call paintComponent literally to execute the body (if it is super.paintComponent it is okay since its calling the super class's paintComponent; the inherited body)** - What if logic of application needs to call paintComponent? - Example: if we are drawing a car and we have code to draw the car and we want to move the car... - We draw the Car by calling paintComponent. Later on, if we want to display the Car elsewhere, we call the method to draw the Car at the other location **repaint** - **Instead of calling paint component literally, if logic of application has to call that part of the code, we can call repaint instead** - VM will call paint component so body can be executed - Typical way of building is-a relationship is extending Jpanel (which is a Jcomponent) - If your class claims to be a Jcomponent, every Jcomponent inherits paintComponent - VM calls paintComponent in three different classes - If logic of application has to execute body, call repaint ![A close-up of a text Description automatically generated](media/image122.png) - In the body: - VM calls paint component and will pass a Graphics object - Graphics objects has a nickname; GraphicsContext - Stores context of Graphic (font of String, color of Object) - Graphics2D - Advanced graphics object - When running programs on later versions of Java, VM will create Graphics2D objects as pass it to you - Graphics2D is a Graphics so its okay to pass a Graphics2D object as a parameter for the method - **Problem: if we call g.Graphics2D specific method (like drawString), it is a specific feature tied to Graphics2D that general Graphics does not have** - Compiler checks type of reference variable g - Graphics does not have drawString method so program does not compile - This is why we cast Graphics g as Graphics2D by copying reference of the same object in another variable - G2.drawString will compile now since Graphics2D comes with drawString - Because G2 is a graphics 2D and G is graphics, we cannot blindly copy references. We need to cast - Need to use g specifically for g2; need to copy reference to specific variable so when we access Graphic objects, we treat it as a Graphics2D object why we cast - Ways we can cast - Primitive types (numbers) - About capacity (64 bits don't fit in 32 bits; so we cast a double to an int loss of information) - Abstract data type - when method header is general but at run time, we get a very specific object and we want to utilize advanced features of the specific object - **We are telling the compiler that even though g is a Graphics type, at runtime we are getting Graphics2D and trust that it compiles** - **No way for compiler to tell** - **Compiler compiles as long graphics and graphics2D has an is-a relationship** - **Flaw: at runtime, if someone passes a non graphics2D object, the cast is aborted** - **Exceptions at runtime if at runtime, the graphics2D object has not been passed** - Cast is usually preceded by instanceof to check if it we are getting the actual object and cast to avoid casting exception - This program doesn't need instanceof because the VM passes graphics2D object, not a random program - No way for VM to pass another object; it will get graphics2D [4.6.4 -- Working with 2D Shapes] - When we program Jcomponent like a Car, we need to describe it using 2D shapes - When we organize all 2D shapes the library, we can have 4 categories - Shapes in each category share common features - Example: Rectangle2D, RoundRectangle2D, Arc2D, Ellipse2D share common features - To describe outline of shapes, we describe boundary box (top-left corner of bounding box, width and height) - Line2D, Quadcurve2D, CubicCurve2D - Describe two end points - Area is a special shape; can perform set operations on the shape (union, se

Use Quizgecko on...
Browser
Browser