combinepdf.pdf
Document Details
Uploaded by WorkableTrigonometry1087
University of Toronto
Full Transcript
CSC207 Software Design Gong Chen Course Website https://mcs.utm.utoronto.ca/~207/24f/index.shtml Class Overview Three Modules (roughly 3-4 weeks each): Java: Non OOP, OOP, GUI Programming Software Engineering: Version Control, Unit T...
CSC207 Software Design Gong Chen Course Website https://mcs.utm.utoronto.ca/~207/24f/index.shtml Class Overview Three Modules (roughly 3-4 weeks each): Java: Non OOP, OOP, GUI Programming Software Engineering: Version Control, Unit Testing, Scrum, Design Pattern Miscellaneous: File I/O, Regex, FSM, Floating Point Numbers, Multithreading Why Java? Different Use Case Scenarios: Python: Data Science interpreter line by line Java: Mobile Apps compiler before execution Faster in Execution: from Interpreter (e.g., Python): Translate source code line by line at runtime translate sourcecode Compiler (e.g., Java): high to low Java Development Kit (JDK): we use JDK 22 Java Runtime Environment (JRE): part of JDK java c compile javac: Compile source code to machine-readable code, e.g., javac HelloWorld.java java: Execute machine-readable code, e.g., java HelloWorld jara execute Entry Point one copy of Only one entry point in a project Static variable method First line of code (LOC) in execution Python: if _ _name_ _ == "_ _main_ _": Java*: public** static*** void**** main(String[ ] args) *: You must write the entry point signature exactly as public static void main(String[ ] args) or main(String... args) **: public is an access modifier ***: static is a keyword, which represents one copy / global copy of this method ****: void is a return type Block and Scope doesnt matter in java Python: indentation Java: { } (Note: indentation does not matter in Java, but is still recommended) Comments Python: single line: # multiple lines: '''... ''' Java: single line: // multiple lines: Naming Convention com.sun.eng Packages com.apple.quicktime.v2 ca.utoronto.utm.mcs.csc207 class Raster; Classes class ImageSprite; run( ); Methods runFast( ); getBackground( ); int i; Variables char c; float myWidth; static final int MIN_WIDTH = 4; Constants static final int LIGHT_SPEED = 300000; Control Flows Java: Sequential default every statement points to the next Conditional: considers different cases - switch - if ( condition )... [[else if ( )... ] else...] Iterative: - while ( condition ) {... [update] } - for( [initialization] ; [condition] ; [update] ) - do {... [update] } while ( condition ) - foreach (Note: similar to Python's for loop) Recursive Conditions Only one boolean expression is allowed, but it can consists of &&s, | |s, and !s. Parentheses can be used to indicate the order of operations for all expression. When parentheses are omitted, the order of operations is determined by precedence rules. Short-Circuit Evaluation: If the first operand associated with an | | is true, the expression is true If the first operand associated with an && is false, the expression is false Not only efficient, but sometimes also preventive: The following code will avoid the run-time error: if ((number != 0) && (sum/number > 5)) Comparisons Using == : if (a == 3) where a is an int if (b == false) where b is a boolean if (c == 'A') where c is a char When not to use == : Floating Points: if (Math.abs(b - c) < epsilon) {... } where b, c and epsilon > 0 are floating point types Strings: StringObj.equals(Other_StringObj), StringObj.equalsIgnoreCase(Other_StringObj) DataTypes Java: Primitive* ** *** ****: - 1 byte: boolean*****, byte - 2 bytes: char******, short - 4 bytes: int, float - 8 bytes: double, long Derived: array, function User-Defined: enum, class *: the most used primitive data types are underscored **: integers have boundaries, and in addition to boundaries, floating point numbers have precision issues ***: every primitive data type has a wrapper class. For example, you can also use Integer i = 5; or Integer i = new Integer(5); instead of int i = 5; ****: byte, short, int, long are all integers. Single-precision floating point and double-precision floating point are all floating point numbers. *****: boolean can also be considered as 1 bit plus 7 bits of slacks ******: char is also an integer, but represents a character. It is based on 16-bit Unicode specification. Unicode is the superset of ASCII code. Type Casting A value of one type can be assigned to a variable of any type further to the right, but not to a variable of any type further to the left: byte -> short -> int -> long int -> float -> double You can assign a value of type char to a variable of type int Class Everything must be in a class. Every class name must be as same as its filename. All classes (directly or indirectly) sub-class the Object class, which consists of the toString( ) method. static The static keyword can be used in various context: variable, method, class, and block Static variables and code exist when the class is loaded into memory. Static code resides in a different memory location than non-static code. Static provides a way to ensure that there is only one copy of a variable or method associated with the class itself, rather than instances of the class. Math, or Wrapper Classes (Question: How about String? indexOf(...) vs. valueOf(...)) Others: constants, configurations, utility methods, shared resources, singleton instances, factory methods CSC207 Software Design Week2 Gong Chen ! Overview Pre- & Post- Increment/Decrement Operators References and Pass-By-Value Data Types (continued) Arrays Classes Pre- & Post-Increment Operators Python: Does not support pre-increment or post-increment. Java: Pre-increment (++i): the value of i increased before it is used. Post-increment (i++): the value of i increased after it is used. What's the output of the following code snippet? int i = 8; System.out.println(i++); System.out.println(++i); 110 System.out.println(i++ * ++i); 120 References and Pass-By-Value reference holds memory address Reference: Unlike primitive data types, a reference hold the memory address of an object. String s = null; s = new String("Hello World!"); Why does Java use references? Java is strictly pass-by-value, meaning that when passing an argument of a method, Java passes a copy of that argument's value. Java passes a copy of an arguments value Arrays Java arrays are used to store a fixed number of elements of the same type. int[ ] num = {1, 2, 3, 4, 5}; int[ ] num = new int[ ]{1, 2, 3, 4, 5}; int[ ] num = new int; String[ ] s = {"Alice", "Bob", "Charlie"}; * int[ ][ ] mat = {{0, 1}, {2, 3}}; Arrays store fixed of elements int[ ][ ] mat = new int; ** mat = 0; mat = 1; of the same time mat = 2; mat = 3; int numLength = num.length; int matRow = mat.length; int matColumn = mat.length; num and mat are all references. Java arrays vs. Python lists vs. Java ArrayList * In Java, double quotes are used for String, and single quotes are used for char. ** In Java, / and % can be used to access and modify a matrix. Class Class vs. Object / Instance UML access modifiers setters & getters constructors overloading static (revisited) scope (revisited) Class vs. Object / Instance class data type refer to stickert object class is just a data type, so similar to int i;, Student stu; will declare a variable stu which can refer to a Student object in the future. On the right hand side of the assignment operator =, new, followed by a constructor, can be used to create / instantiate an object at runtime. now istantiates an object at runtime used for visualizing how classes interact UML unified modeling language variables Unified Modeling Language Class diagrams are the building blocks of UML Access modifiers and keywords in UML: -: private ~: default #: protected +: public i underlined: static important Access Modifiers for encapsulation Access modifiers are used to set the visibility and accessibility of classes, methods, and variables. Access modifiers play a crucial role in encapsulation. Modifier Class Package Subclass World private Yes No No No default Yes Yes No No protected Yes Yes Yes No public Yes Yes Yes Yes How about Python? Setters & Getters Setters / Mutators: set update used to set or update the value of a private field access modifier: public have a void return type (Note: void is a return type) Can be used to (re)set each attribute one by one Getters / Accessors: retreive used to retrieve the value of a private field access modifier: public have no parameters Are not required if specific attributes should not be exposed Constructors acts as blueprint of class Unlike int i = 5; that you can easily initialize i with just an integer, an object can hold many data members / attributes (and methods). Therefore, we need to come up with a way to initialize those attributes altogether. The only goal of constructors: initialization goal initialization There may be zero to many constructors in your code. Types: Default: a constructor with no parameters, whether using default values or not no constructor detainment Note: If no constructor in your code (like what you see on the previous slide), Java compiler will create a default constructor with default values, such as 0 for int, 0.0 for double, false for boolean, null for arrays and classes. Parameterized: a constructor with at least one parameter Copy: It is analogous to a sample for mass production in an assembly plant. Constructors vs. Methods no return type same rare isreturn type Naming and Syntax: A class Constructors: Have no return type, and their names must be same as the name of the class Methods: Have a return type, and their names can be anything (descriptive verbs are recommended) Purpose: Constructors: Initialize newly created objects initialize new object Methods: Define behaviors and return values upon the executions define behaviour and Invocation: return values Constructors: Implicitly invoked by the system and triggered by new triggered by new Methods: Explicitly invoked by the programmer on an already created object Note: Setters are a special method. Overloading Three types of overloading: 3types Method overloading: Method Allows two or more methods in a class with the same name and different parameters 2t methods in class samename diffparam A method signature, used for checking method uniqueness at compile time, consists of a function name as well as the number, type, and order of its parameters order of parameter One of the complications: implicit type conversion pretttypeconversion auto type conversionbycompiler Constructor overloading: constructor Similar to method overloading With this([param(s)]) as well as super([params]), we can use constructor chaining for invocation Operator overloading: constructor chaining In C++ only, but in Java, + can be used for either addition or concatenation static (revisited) belongs to class itself not instance Static variable (a.k.a. class variable, e.g., Math.PI) belongs to the class itself rather than to any specific instance of the class. Questions: Can a static variable reside in a static method? Yes they can access v2 belong to chase Can a static variable reside in a non-static method? yes static variable share everywhere Can an instance variable reside in a static method? No belongs to class has no instene variables scope (revisited) Unlike self in Python, this may be optional. However, you should be aware of the scope... Let's dig into the code :-) CSC207 Software Design Week3 Gong Chen Overview Software Engineering: Documentation with Javadoc Unit Testing with JUnit Java: Inheritance Abstraction Abstract Class Polymorphism overloading vs. overriding final UML (revisited) Collections Framework ArrayList Software Documentation Types: internal comments structure doc development guide Internal Documentation (e.g., comments in source code, code structure documentation, development guides): Helps developers understand the codebase helps understand codebase Facilitates collaboration among team members makes collaboration easier Aids in maintenance and future development better maintenance and future External Documentation (e.g., user manuals, installation guides, API documentation): developmen Guides end-user in using the software guide external user manuals APIdoe Provides installation and setup instructions fukstallation setup instructions Offers troubleshooting help and FAQs offers troubleshooting help and FAQs API documentation is aimed at developers who will use the API to integrate with or extend with software. API set of rules and tools that allows for communication between different software applications Javadoc A software tool for generating API documentation format in HTML format from Java code Javadoc comments: dos java start with include tags, such as @param, @return, @author, @since, @version Command Line Tool: javadoc [-d dst-dir] {src-files} Note: See https://docs.oracle.com/javase/8/docs/api/ Also see https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html Javadoc Examples Testing Activities in Software Quality Assurance (SQA) Verification: "Did we implement the system right?" Validation: "Did we implement the right system?" Technical Reviews: Code review, document review, etc. Testing: Aimed at discovering issues in the software Software Testing: a dynamic validation activity aimed at identifying defects and undesirable behaviour in the software, ensuring it meets all requirements and constraints. While the focus is on uncovering functional errors rather than syntax errors, test cases are meticulously crafted to maximize the likelihood of discovering problems. Roles: Developers: Familiar with the system but often test in a "gentle" manner, prioritizing delivery. Independent Testers: Take the time to understand the system, with the objective of pushing its limits, prioritizing quality. Testing (Cont'd) Types: Unit Testing (for individual components, class, or subsystem): unit testing individual components Confirms that the component or subsystem is correctly implemented and performs the intended functionality integration groups of subsystems Integration Testing (for groups of subsystems and, eventually, the entire system): Tests the interfaces between subsystems System Testing (for the entire system): entiresystem Assesses whether the system meets both functional and non-functional requirements Acceptance Testing: system entire system Validates that the system meets the specified requirements and is ready to use Acceptance validates that system meets seeitic requirements and is ready to use Unit Testing in Java JUnit 5 is a testing framework for Java that provides a comprehensive solution for writing and running tests Key Components: Feature Platform Jupiter Vintage Backward compatibility for old JUnit Purpose Foundation for test engines New programming model for tests tests Functionality Test Engine API, test discovery Annotation, Assertions, extensions Compatibility layer for JUnit 3/4 Test Execution Runs tests from various frameworks Executes tests written with Jupiter APIs Executes legacy tests as part of JUnit 5 Modern Features N/A Supports dynamic and nested tests N/A JUnit 5 Annotations Test mark as test case should be executed Mark a method as a test case that should be executed by the testing testing framework byframework @Test void nameTheTestMethodDescriptively( ) {...assert... } BeforeEach executed before each test method in awnedt.se Specify that the annotated method should be executed before each test method in the current class @BeforeEach void setUp( ) { // Code to set up test environment } AfterEach run after each test method Indicate that the annotated method should run after each test method @AfterEach void tearDown( ) { // Code to clean up after tests }... JUnit 5 Assertions Assertions are used to validate that the code under test behaves as expected Basic Assertions: assertTrue(test) Asserts that a condition is true assertFalse(test) Asserts that a condition is false assertEquals(expected, actual) Asserts that two values are equal assertNotEquals(unexpected, actual) Asserts that two values are not equal assertNull(value) Asserts that an object is null assertNotNull(value) Asserts that an object is not null JUnit 5 Examples Setting up JUnit 5 (in pom.xml if Maven): Source Code & Test Code: Running the Tests: mvn test code reuse is a Inheritance inherits data fromexisting class behaviours Inheritance is a mechanism for code reuse that allows you to create a class that inherits data and behaviours from an existing class while also enhancing it with new capabilities. You can specify that a new class, known as a subclass or derived class, should inherit the members of an existing class, referred to as superclass or parent class or base class. Syntax: subllass should inherit superclass public class subclass extends superclass {... } extends Subclasses automatically inherit all instance variables and methods from their superclass. subclasses inheit all instance var's and methods In Java, a subclass can extend only one superclass. Java does not support multiple inheritance (i.e., extending two or more superclasses); instead, it uses interfaces to achieve similar functionality. The is-a relationship (i.e., inheritance) vs. The has-a relationship (i.e., composition) Models an is-a relationship with inheritance: public class MilliTime extends Time {... } Models a has-a relationship with an attribute: public class Event {... private Time... } Inheritance (Cont'd) universal superclass The java.lang.Object Class: Universal superclass for all other classes in Java Have several important methods, such as toString, equals, hashCode, clone, getClass If a class header does not include the extends clause, the class automatically extends the Object class by default. super: class auto extends Object super.method([parameters]) super([parameters]) every super.super.method(... ) Used to access protected or public fields and methods from the super class that has been overridden ability to perform Polymorphism a task in multiple ways partic methods Polymorphism refers to the ability to perform a task in multiple forms or ways, particularly in the context of functions or methods. It allows objects to determine which version of a function to execute, both at compile-time (static polymorphism) and at run-time (dynamic polymorphism). allows objects Types of polymorphism: compile overload todetermine which - compile-time: version of function Ad-hoc Polymorphism: method overloading Parametric Polymorphism: generics to execute Coercion Polymorphism: casting - run-time: method overriding (used to determine the "right" method to execute) Dynamic polymorphism reduces need for type casting method overriding // Non OO style: if (numbers[i] instanceof Integer) runtime sum += ((Integer)numbers[i]).doubleValue(); else if (numbers[i] instanceof Double) sum += ((Double)numbers[i]).doubleValue(); Note: instanceof can guard against ClassCastException // OO style: sum += numbers[i].doubleValue(); conceals complex Abstraction implementation exposing only relevant features to users Abstraction focuses on concealing the complex implementation detail of a system and exposing only the essential and relevant features to users. abstract classes: Unlike concrete classes which can be instantiated to create objects and provide complete implementations for all of its methods, abstract classes are incomplete with methods declared without an implementation, so cannot be instantiated. Abstract classes are used to provide a common interface and base functionality for subclasses while leaving specific details to be defined by those subclasses. Key characteristics: abstract Class common interface base func methods not implemented Inheritance: Used to define a common base for related classes, enabling polymorphism Concrete methods: methods with implementations that subclasses can inherit or override Abstract methods: methods, which define the expected behaviour without providing the details, must be implemented by any concrete subclass Cannot be instantiated Can have constructors can't be instantiated can have constructor rewrites Method Overriding method fromsuperclass if needs not met Subclasses inherit all methods from their superclass. However, there are instances where the implementation of a method in the superclass does not meet the needs of the subclass. In such cases, the method must be overridden. The overriding method in the subclass must have the exact same signature as the method it overrides in the superclass. Key points: When you call func on an instance of B, the implementation in B (i.e., bodyB) runs. You can access the superclass method using super.func(...) within the subclass to call the original method. The overriding method in the subclass must have the same return type as the method in the superclass. If the superclass method returns int, the subclass method must also return int. Method Overloading vs. Method Overriding compile run time Feature Method Overloading Method Overriding What same method name, different parameters same method name and parameters Why improve code readability provide specific implementation in subclasses When compile-time run-time Where within the same class or subclass in subclass can't be changed final once initialized Final Variables: cannot be changed once it has been initialized Syntax: Benefits: Thread Safety: Safe in multi-threaded contexts, reducing concurrency issues thread safety errorreduction Immutability and Error Reduction: Prevent accidental reassignment, leading to fewer bugs Final Methods: Cannot be overridden by subclasses for ensuring the method's behaviour remains consistent Syntax: Benefits: cannot beoverriden performance security Security: Prevent subclasses from altering critical functionality Performance: Since final methods cannot be overridden, the compiler can optimize calls to them, reducing polymorphic overhead at runtime Final Classes: Cannot be extended, that is, no subclasses can inherit from a final class can't be Syntax: extended no subclasses Benefits: design clarity Design Clarity: It clearly indicates that the class is complete and should not be modified Performance: Eliminate the need for dynamic method resolution, potentially improving performance performance UML (revisited) Attributes: visibility name : type Methods: visibility [] methodName(param1: type, param2: type): returnType Abstract Class: Relations: Collections Framework allows management and Object of a group of objects meet manipulation as singly Collection: An object that represents a group of objects, allowing you to manage and manipulate them as a single unit Collections Framework: Provides a unified framework for representing and manipulating collections. This framework allows manipulation to be independent of the underlying implementation details. Advantages: provides unified framework Reduce Programming Effort: It offers ready-to-use data structures and algorithms, reducing the need to write custom code Increases Performance: High-performance data structures and algorithms are available, optimizing data handling and processing Interoperability: Different collections can work together seamlessly, allowing for easier integration and manipulation Common Language: It provides a consistent set of interfaces and methods for manipulating collections, enhancing code readability and maintainability Components: Interfaces: Define the basic functionalities that collections should provide. Common interfaces include Collection, List, Set, and Map Implementations: Concrete classes that implement the collection interfaces. Examples include ArrayList, HashSet, and HashMap Algorithms: Standard methods for manipulating collections, such as sorting, searching, and shuffling. These algorithms can be applied to any collection that implements the appropriate interfaces ArrayList desizable array A resizable array implementation of the List interface in Java Key features: Dynamic Sizing: Can grow or shrink as needed, unlike fixed-size arrays Index-Based Access: Elements are accessed via their index (starting at 0), enabling quick retrieval Type-Safety with Generics: Can specify the element type (e.g., ArrayList), enhancing type safety and reducing errors Performance: Access operations are O(1) on average, but adding/removing can be O(n) in the worst case due to potential resizing Null Values: Support storing null elements CSC207 Software Design Week4 Gong Chen Overview Function (revisited) Polymorphism (revisited) Generics Interface with List Abstract Class vs. Interface GUI Programming with JavaFX Collections Framework (revisited) Package Function (Revisited) invocation of method thatexecutescode define A function call is an invocation of a method that executes the code defined within it. Syntax: methodName(arguments); static method: Math.abs(-3.14); non-static method: Student stu = new Student( ); stu.getUTORid( ); The Swap Function: Purpose: To interchange the value of two variables Note: Java uses pass-by-value, so changes to parameters do not affect original variables What's the output of the following code? changes to param public class SwapExample { do not affect og public static void swap(int a, int b) { // Note: this is a wrong version int temp = a; a = b; b = temp; values } public static void main(String[ ] args) { int a = 2, b = 3; swap(a, b); System.out.println("a: " + a + ", b: " + b); // a: 2, b: 3 } } Function (Revisited) Correct version: public class SwapExample { public static void swap(int[ ] numbers) { int temp = numbers; numbers = numbers; numbers = temp; } public static void main(String[ ] args) { int[ ] nums = {2, 3}; System.out.println(“Before swap: a = ” + nums + “, b = ” + nums); swap(nums); System.out.println(“Before swap: a = ” + nums + “, b = ” + nums); } } Key Takeaways: Pass-by-Value: Java does not swap original values in the wrong version using primitive data types Java is always pass-by-value: For objects, it's the value of the reference. If you want to modify the original values of variables, you typically need to use an array or an object Polymorphism (Revisited) - Generics Generics allows you to write code that can operate on objects of various types while ensuring compile-time type safety A generic class is defined using the syntax, where T stands for "Type" code that can Benefits: generics Type safety: helps catch type-related errors at compile time on Objects of various operate fi Code reusability: allows for a single method or class to operate on various types compile Elimination of type casting: reduces the need for explicit casting types while ensuring type safety Generic Collections in Java: Java's Collections Framework uses generics extensively to enforce type safety List list = new ArrayList( ); list.add("Alice"); list.add("Bob"); list.add(123); // compile-time error String s = list.get(0); Raw types, which should be avoided: List list = new ArrayList( ); list.add("hello"); list.add(123); String s = (String) list.get(0); Polymorphism (Revisited) - Interfaces interfaces reference type that that has constants and methods An interface in Java is a reference type that can contain constants, method, default methods, static methods, and nested types. Its purpose is to define a contract for classes to implement, enabling multiple inheritance of type. Key features: Abstract methods: All methods are implicitly public and abstract all methods abstractpatic No method body: Interfaces cannot provide method implementations cannot implement Multiple inheritance: A class can implement multiple interfaces class can implement multiple interface Polymorphism (Revisited) - Interfaces First Example (e.g., with one interface): Define an interface: Use the classes: Implement the interface in classes: Polymorphism (Revisited) - Interfaces Second Example (e.g., with two interfaces): Define two interfaces: Implement the interfaces in one class: Use the class: Abstract Classes vs. Interfaces Abstract Classes Interfaces Variables static and non-static static Access Modifiers all, except private public only Speed Fast Slow When to Use Avoid Independence Future Enhancement GUI Programming with JavaFX library JavaFX is a library for building rich, interactive client applications in Java. It is designed to serve as a modern alternative to Swing, providing a more flexible and feature-rich toolkit for developing graphical user interfaces (GUIs) Key Architecture Components: Stage: The top-level container for a JavaFX application, representing the main window top level container representing main window Scene: The container for the content displayed within the Stage. Scenes can be dynamically changed during runtime. content displayed within stage Nodes: The basic building blocks of a JavaFX application. Nodes represent all visual elements, such as buttons, text, images, and other graphical components. all visual elements buttons text images GUI Programming with JavaFX Package namespace that organizes set of related classes and interfaces A package is a namespace that organizes a set of related classes and interfaces. It helps in avoiding name conflicts. Packages also provide access protection and easier code maintenance. Types: Built-in packages: User-defined packages: Recall (Access Modifiers): public: accessible from any other class or package protected: accessible within the same package and subclasses within package subclass default (package-private): accessible only within the same package default withpackage Static import allows you to access the static member of a class directly without using the fully qualified name. import static java.lang.Math.*; double d = abs(-3.14); import static java.lang.System.out; static import out.println("Hello World"); don't have to use fully qualified name Collections Framework (Revisited) List Map CSC207 Software Design Week5 Gong Chen Overview Java: GUI Programming: JavaFX (revisited) Software Engineering: Software Process: Scrum Design Pattern: Model-View-Controller (MVC) JavaFX JavaFX (Cont'd) JavaFX (Cont'd) javafx.graphics (https://openjfx.io/javadoc/22/javafx.graphics/module-summary.html): JavaFX (Cont'd) Application (https://openjfx.io/javadoc/22/javafx.graphics/javafx/application/Application.html): entry point 1 Stage (https://openjfx.io/javadoc/22/javafx.graphics/javafx/stage/Stage.html): top line The JavaFX Stage class is the top level JavaFX container. The primary Stage is constructed by the platform. Additional Stage objects may be constructed by the application. Stage objects must be constructed and modified on the JavaFX Application Thread. JavaFX (Cont'd) width height rendered scene defines scene to be node leaf or branch Scene (https://openjfx.io/javadoc/22/javafx.graphics/javafx/scene/package-summary.html): Event Handler (https://docs.oracle.com/javase/8/javafx/events-tutorial/processing.htm): used to handle user interactions An interface that defines the handle( ) method to process events processevents Common event types: MouseEvent (e.g., mouse click, mouse movement) KeyEvent (e.g., key press or release) ActionEvent (e.g., button click or menu selection) How to set an event handler: Create a handler by implementing the EventHandler interface Attach the handler to a UI control using setOn... methods implement Example: Software Process A structured set of activities for developing software systems, including: structured set of activities developing software system Team standards, practices, and conventions for Descriptions of how a team works Synonyms: Software development methodology Software development life cycle In essence, it outlines how a team: teen Decides what to build outlines how Builds it Evaluates the result results evaluates Software Development vs. Other Products At first glance, building a software product shares similarities with building other technical products. Therefore, many software development processes use a sequential (non-iterative) model, often referred to as the Waterfall Model, where progress flows steadily downward through these phases: Requirement Analysis waterfall method sequential Design Construction Testing (Verification) Maintenance Cons of the Waterfall Model The Iron Triangle in software development refers to the three core constraints that affect the success of a project: Time: The schedule or timeline for the project time cost Cost: The budget allocated to the project scope Scope: The features and functionality of the project These constraints are interconnected: Time vs. Cost: Rushing a project may increase costs due to additional resources or overtime rushing costs Cost vs. Scope: Lowering the budget may force compromises on features cost features Scope vs. Time: Reducing time may leading to cutting features or reducing testing time features testing Early Alternative — Spiral Model Waterfall Failures: waterfall bad for bigprojects The Waterfall model failed for large projects (e.g., over budge or incomplete) This led to incremental development with iterations, similar to smaller waterfalls planning estimation scheduling Spiral Model (Iterative Development): risk analysis Gather requirements communication modeling Build prototype (e.g., mock UI) analysis design Collect feedback start Adjust based on feedback complex constant deployment However, the Spiral Model still have some drawbacks: delivery construction code Complex and resource-intensive: It requires constant planning and risk analysis platelmansis feedback test High cost: Frequent iterations and extensive risk management increase project expenses “It could be out of control...” Slower delivery: Long cycles and continuous revisions can delay the overall timeline show delivery high cost Agile As development models evolved, they encouraged software teams to: Be more flexible and adaptive to changing requirements Collect frequent feedback from users Release code more regularly Emergence of Agile flexibility adaptability Agile = Mindset, Not a Process Focuses on flexibility and adaptability, ideal for projects with changing requirements Applied across various processes, models, and teams Agile manifesto (source http://agilemanifesto.org): good for projects Individuals & interactions > processes & tools Working software > comprehensive documentation with changing Customer collaboration > contract negotiation Responding to change > following a plan Note: The right side has value, but the left is prioritized requirements Agile Frameworks Common Agile Frameworks: Scrum Kanban Extreme Programming (XP) Lean Crystal Scrum: Scrum: A Flexible Product Development Framework collaborative iterative Scrum is a collaborative, iterative approach for managing software development projects, where the team works towards a common goal Key Process: while(!isProjectFinished) { Plan -> Build -> Test -> Review } Sprints: Fixed-Length (1 week to 1 month) build test Each Sprint: Begins with planning & task estimation Results in a potentially deliverable product plan Raig Releases: Composed of multiple sprints Produce shippable software Backlog: Prioritized set of features / work requirements for each sprint Flexibility: Adapts to changing customer needs Embraces quick delivery and response iteration Scrum Team communicates vision supposed to do what product is knows Product Owner: maintain backlog Communicates the vision of the product Knows what the product is supposed to do Maintains a product backlog Prioritize user stories (i.e., desirable features) The Team (e.g., Analysts, Designers, Developers, Testers): Designs and builds what the product owner wants ScrumMaster: Serves both product owner and team Design Patterns: A Solution Framework general solution using specifiedarrangement Definition: A design pattern is a general solution to a common problem using a specific arrangement of classes and objects commonproblem Key Points: classes and objects implementation Describes code structure, not implementation details codestructure not A way to communicate design ideas communicate design Language-agnostic no language promoted Origin: Codified by the "Gang of Four" in 1995 Categories: Creational (e.g., factory) Structural (e.g., composite) Behavioural (e.g., observer) Motivation Example Technically, you could implement everything in a single large file, but is there a more efficient way? How would you divide the work if two people were collaborating? What are the software's key components? If you change the front-end design, do you need to update the entire codebase, or just specific parts? Model-View-Controller encapsulates app state reneders behaviour requests user actions updates one for each functionality Model-View-Controller (Cont'd) Roles data Model: appstate internal Knows only the application state and internal data Does not interact directly with the view View: Sends events to the controller Reflects changes in the model (user interface) UI Controller: Receives events triggered by the view Manipulates the model and updates the application state Acts as a bridge between the model and view, ensuring the view is updated when the model changes Note: In practice, the view and controller are often tightly coupled Advantages of MVC Better Extensibility and Reusability extensibility resusability MVC’s modular structure allows for quick development of new applications without rewriting existing code Improved Collaboration collaboration Independent development of Model, View, and Controller reduces communication overhead and boosts efficiency Cleaner, More Maintainable Code clearer moremaintenable MVC promotes organized, modular code, making it easier to manage, maintain, and scale Observer Design Pattern change in subjecttriggersupdates Observer Design Pattern defines a one-to-many dependency where a change in the subject triggers updates to all dependent observers Key Components: on tomanydependency to all dependent observers Subject / Publisher (e.g., class Observable): Maintains a list of observers, and provides methods to attach, detach, and notify observers Subscriber (e.g., interface Observer): Defines an interface for receiving updates from the subject maintains list receivingupdates ConcreteSubject: Sends notifications to observers when its state changes fromsubject attiffetam sends notifs ConcreteObserver: Updates itself based on changes in the subject Advantages: updatesitself Loose Coupling: Reduces dependency between the publisher and subscribers reamersdependency Flexibility: Enables dynamic addition / removal of subscribers removal dynamiladdition Support for Event-Driven Systems: Facilitates real-time communication of updates Use Cases Event-driven systems (e.g., GUI frameworks) eventdriven systems Notification Systems (e.g., email/SMS alerts) motifsystems Real-time data feeds (e.g., stock market, weather updates) real time data Relation Between MVC and Observer maintaining data notifying model subject In MVC, the Model acts as the Subject in the Observer pattern, maintaining data and notifying the View (the Observer) of any state changes Vi alto updates The View automatically updates the UI in response to changes in the Model, without direct communication between the two simplifies view updates Using the Observer pattern simplifies view updates, eliminating the need for the Controller to manually update the View, promoting a decoupled and scalable system decoupled Example — Magazine Subscription Scenario: Imagine a magazine publisher that releases new issues. As a customer, you can subscribe to receive each new issue as it's released Process: Subscription: You subscribe to the magazine, and each time a new issue is released, it is delivered to you. You stay subscribed until you choose to unsubscribe Unsubscription: You can unsubscribe at any time. Once unsubscribed, you no longer receive future issues, but the publisher continues releasing magazines and other subscribers continue to receive updates Key Concepts: Publishers: The magazine publisher (the subject) manages its business and maintains a list of subscribers Subscribers: Each subscriber (the observer) receives the latest issue when it's published. If a subscriber unsubscribes, they are removed from the list, but the publisher continues its operations Example — Magazine Subscription (Cont'd) Example — Magazine Subscription (Cont'd) Design Pattern: Observer and Observable dependentobservers auto notify What it achieves: The Observer pattern allows an observable object to automatically notify all of its dependent observers when its state changes Making a class Observable: at statechange extend Observable To make a class observable, extend the Observable class You can override the following methods: notified changes registers addObserver(): Registers an observer to be notified when the observable changes observable changed true setChanged(): Sets the "changed" flag to true, indicating that the state of the observable has changed notifyObservers(): Notifies all registered observers about the change notifies our observes Making a class an Observer: implement aboutchange To make a class an observer, implement the Observer interface You must override the update() method, which is called when the observable notifies the observer of a change updated when observablenotifies observer of change CSC207 Software Design Week6 Gong Chen Overview Git Design Patterns: Behavioural: Observer (revisited) Iterator Creational: Singleton Git Overview distributed versioncontrolsystem software dev Git is a distributed version control system used to track changes in source code during software development trackchanges insourcecode It allows multiple developers to work on the same project without overwriting each other's work multipledevelopers Key features: w o overwriting Version Control: Track changes, manage project history Branching: Create branches for new features or bug fixes branching Merging: Combine changes from different branches merging Basic Git commands: Git commands Introduce yourself to Git To set up your identity, enter the following commands: git config --global user.name "Jane Doe" git config --global user.email "[email protected]" You only need to do this once If you want to use a different name or email address for a specific project, you can change it just for that project Navigate to the project directory (i.e., cd ) Run the same commands, but omit the --global flag Git Terminology current commit of HEAD: repo Refers to the current commit your repository is pointing to Usually points to the latest commit on your current branch, but not always HEAD^: parent of HEAD aparent HEAD~4: great-great grandparent of HEAD If HEAD is not at the tip of any branch, it's called a "detached HEAD" master main branch The default branch created when initializing a Git repository (i.e., default development branch) In most cases, "master" represents the main branch, which is the definitive view of the repo. Common for release branches to be made off master Your local master usually mirrors the master branch of the remote repo origin The default name given to your main remote repository (i.e., default upstream repo) Typically when you push your local changes main remote repo "origin" is the standard name, but it's not a requirement Key Takeaway: HEAD is well-defined Git concept, while master and origin are common names, but not mandatory Git Locations Working Directory local changes made here Where your files are stored locally Changes are made here Staging Area (Index) after git add Holds changes that are ready to be committed ready to comit Files moved here with git add stores committed changes Repository (Git Repo) Stores committed changes Managed with Git commands like git commit Remote Repository shared version of nepo A shared version of your repository (e.g., on GitHub, GitLab, Bitbucket) Communicated with via git push and git pull a repo git pull gitpush a repo Working Locally Create a new repository*: git init Commit and update a file with add and commit to staging Show differences: compare working git diff (compare the working directory to the staging area) git diff HEAD (compare both unstaged and staged changes to the last commit) Use git status frequently to check the current status of the repository *: Given that you clone a repository, you don't have to do this am status of repo Interacting with a Remote Repository Add a remote repository to your local Git repository*: git remote add , you can verify with git remote -v Push to a remote repository: git push [:] First time pushing a branch: git push --set-upstream origin Best Practice: Always pull before pushing your changes If conflicts arise: 1. Fetch the latest changes 2. Resolve merge conflicts 3. Checkout the resolved branch *: You don't need to do this in CSC207, since git clone automatically sets up a default remote repository for you. However, you may need to run this command once in one of the following four situations: - When initializing a new Git repository locally and you want to connect it to a remote repository - When you delete or remove an existing remote and need to reconnect it - When you move or copy a repository locally and need to re-establish the connection to the remote - When you’re creating a new remote connection after starting a repository from an existing codebase or project Branching & Merging Commit objects in a Directed Acyclic Graph 0 parents -> initial commit 1 parent -> ordinary commit 2 parents -> merge commit Create a new branch: git checkout -b Branching & Merging Switch between branches: git checkout [-m] Merge a branch: git merge Branching & Merging Git merge conflicts happen: Where: Both working locally or with remote repositories both local remote When: Two developers modify the same part of the same file modify samepart of samefile A developer merges different branches merges diff branches Resolve merge conflicts: Files with no conflicts: Automatically added into the staging area (index) Files with conflicts: If the same file is modified in both branches, it remains in the working directory and is marked as "unmerged" Textual files: Merged on a per-line basis Conflict zones: enclosed within > Binary files: Always cause conflicts and require manual resolution Observer Observer Design Pattern: notify observers needing w o toucheckousy allows a subject to notify observers of changes without them needing to check continuously General Implementation: ofchanges er er Observer (Cont'd) Java Implementation: Observer (Cont'd) Push mechanism (e.g., stock market price updates pushed to an app every minute): manages delivery Data delivery: Subject sends data to observers subject Responsibility: Subject manages data delivery Use case: frequent updates (e.g., notifications) Pull mechanism (e.g., a weather app that checks the temperature only when the user opens it): observers requestformsubject Data delivery: Observers request data from the subject observes Responsibility: Observers controls when to fetch data control Use case: On-demand data retrieval (e.g., polling) Iterator Iterator design pattern: sequential access toelements allows sequential access to elements of a collection without exposing its underlying representation and provides a way to access the elements of an aggregate object (e.g., a collection) one at a time without exposing its internal structure aggregate objet Use cases: Wo exposing internalstructure Java built-in collection: ArrayList, HashSet, Stack Real-world: music album, Git log, Facebook friends Goals: Provide a consistent mechanism to traverse any collection Encapsulate the internal structure of the collection Iterator (Cont'd) Key components: Iterator Interface: Defines methods to traverse through the collection hasNext( ): Checks if there is another element next( ): Returns the next element Concrete Iterator: Implements the Iterator interface to iterate through the collection Iterable Interface: Defines a method to create an iterator Concrete Iterable: Implements the collection, storing the elements Iterator (Cont'd) Collection c; Collection c; Iterator it = c.iterator( ); for (Object o : c) { while (it.hasNext( )) { print(o); print(it.next( )); } } Creational Design Patterns Singleton Chase has only Singleton design pattern: instance provides globed point to ensures a class has only one instance and provides a global point of access to that instance access that instance Use cases: Control access to shared resources (e.g., database connections) control access to shared resources Require only one instance of a class (e.g., logging, configuration) one instance What we expect (Note: the following code is incorrect): // create a new object of Singleton Singleton s1 = new Singleton( ); // s1 and s2 are referring to the same instance of the Singleton class Singleton s2 = new Singleton( ); Singleton (Cont'd) Valid implementation #1: public final class Singleton { private static final Singleton INSTANCE = new Singleton( ); private Singleton( ) { } public static Singleton getInstance( ) { return INSTANCE; } } When is the instance created? Right after the program starts Singleton (Cont'd) Valid implementation #2: public class Singleton { private static Singleton instance = null; private Singleton( ) { } public static synchronized Singleton getInstance( ) { if (instance == null) { instance = new Singleton( ); } return instance; } } When is the instance created? When the first time you use the Singleton class (i.e., lazy initialization) Singleton (Cont'd) What we expect: // create a new object of Singleton Singleton s1 = Singleton.getInstance( ); // s1 and s2 are referring to the same instance of the Singleton class Singleton s2 = Singleton.getInstance( ); referring to same Key features: private constructor no instant 1 n Private constructor: Prevents instantiation from outside the class Static instomer Static instance: Holds the single instance Single instance Public method: Provides access to the instance public method CSC207 Software Design Week7 Gong Chen Overview Midterm Design Patterns: Creational: Factory Behavioural: Strategy Command Structural: Composite Midterm Exam Coverage Week1 - Week6 Design Patterns: Creational: Factory Behavioural: Strategy Command Structural: Composite The S O L I D principles The SOLID principles are a set of five design principles intended to help software developers create more maintainable, understandable, flexible and scalable object-oriented software systems. The acronym SOLID stands for: - Single Responsibility Principle (SRP) - Open/Closed Principle (OCP) - Liskov's Substitution Principle (LSP) - Interface Segregation Principle (ISP) - Dependency Inversion Principle (DIP) Single Responsibility Principle: "A class should have one, and only one, responsibility and reason to change" Open/Closed Principle: "A class should be open for extension, but closed for modification" Single Responsibility Principle Before SRP: After SRP: The AlarmClock class does two things: Setting the alarm time Playing the alarm sound Open/Closed Principle Before OCP: After OCP: In this code, if we want to add more cities, we need to modify the CityInfo class every time Factory One of the most used design patterns in practice Comes in different variations and implementations: Factory vs. Factory method vs. Abstract Factory Example: Imagine a car factory that builds different types of cars (sedans, trucks, etc). The factory decides which type to create based on some input (e.g., configuration, request), while the client is only interested in receiving a car, not the details of its creation Factory Pattern Is this code SOLID? Note: For CSC207, as long as you understand the basic Factory Pattern, you'll be well-prepared to work on Assignment 2 Factory Method Pattern Abstract Factory Pattern When To Use Which? Factory Pattern: Responsible for creating objects based on input (direct instantiation) Factory Method Pattern: Ideal for single product variations Abstract Factory Pattern: Suited for families of related objects Abstract Factory Pattern (Cont'd) Strategy Purposes: Selects an algorithm at runtime Defines a family of interchangeable algorithms Benefits: Allows dynamic decision-making Improves flexibility and maintainability Enables algorithm changes without modifying the client When to use: Use cases: When your app has an "algorithm" component Payment Systems When you need interchangeable algorithms Sorting Algorithms To change algorithms dynamically at runtime To encapsulate algorithms in separate files for independent development Compression Techniques Strategy (Cont'd) Components: Client: Configures the Context and selects the appropriate strategy Context: acts as the orchestrator that delegates to the strategy Strategy: encapsulates interchangeable algorithms ConcreteStrategy: Implements specific algorithm versions Command Purposes: Encapsulate a request in an object Allows the parameterization of clients with different requests Allows saving the requests in a queue Use cases: Transactional Systems: Execute sequences of operations with rollback on failure Undo/Redo Actions: Encapsulate operations as commands within text editors or drawing apps Remote Control Systems: Trigger actions without knowing buttons' implementation details Components: Client: creates a ConcreteCommand object and sets its receiver Invoker: asks the command to carry out the request Receiver: knows how to perform the operations Command: declares an interface for executing an operation ConcreteCommand: extends the Command interface, implementing the Execute method by invoking the corresponding operations as Receiver. Command (Cont'd) Command (Cont'd) The customer (Client) sends his request to the cook (Receiver) through the bartender (Invoker). The bartender encapsulates the order (Command) by writing it on a check (ConcreteCommand) and then send it to the cook. Command (Cont'd) Invoker Receiver Command ConcreteCommands Client Composite Structure: Component: Common interface for all objects Leaf: Individual objects (no children) Composite: Objects with children When to use: For recursive structures (i.e., components containing other components, e.g., file systems or organizations) When following a tree-like structure / part-whole hierarchy (e.g., graphics) Key benefits: Simplifies code: Threats objects and compositions the same Extensible: Easily add new components Flexible: Modify the structure without affecting other parts Composite (Cont'd) rectangle A graphic is composed of smaller graphics circle car Simple circle Graphic Components whole picture Composite Graphic Components triangle tree rectangle An arithmetic expression is composed of smaller arithmetic expressions (1+2) * (3-4) 1 (1+2) 2 Simple (1+2) * (3-4) Composite Expression Components Expression Components 3 (3-4) 4 Composite (Cont'd) Goal: Handle both Leaf and Composite nodes uniformly Clients do not need separate handling for simple and composite objects How to implement: 1. Define a common interface for components 2. Implement: 1. Leaf (simple component) 2. Composite (contains children) 3. Composite typically allows to add elements 4. Clients use the interface without differentiating between types