Client Code - the code that uses the classes under discussion. Coupling - code in one module depends on code in another module

Similar documents
Programmazione. Prof. Marco Bertini

CS112 Lecture: Defining Instantiable Classes

QUIZ. What is wrong with this code that uses default arguments?

The name of our class will be Yo. Type that in where it says Class Name. Don t hit the OK button yet.

QUIZ Friends class Y;

QUIZ on Ch.5. Why is it sometimes not a good idea to place the private part of the interface in a header file?

Singleton, Factory Method, Abstract Factory, Named Constructor. Using one or more base classes to hide details from the client

Chapter 9 :: Data Abstraction and Object Orientation

And Even More and More C++ Fundamentals of Computer Science

Data Abstraction. Hwansoo Han

CS112 Lecture: Defining Classes. 1. To describe the process of defining an instantiable class

Software Engineering /48

Lecturer: William W.Y. Hsu. Programming Languages

Programming Style. Quick Look. Features of an Effective Style. Naming Conventions

Heuristic Evaluation of Team Betamax

Chapter 10 :: Data Abstraction and Object Orientation

Item 4: Extensible Templates: Via Inheritance or Traits?

CPS122 Lecture: Course Intro; Introduction to Object-Orientation

Programming in C++ Prof. Partha Pratim Das Department of Computer Science and Engineering Indian Institute of Technology, Kharagpur

Chapter01.fm Page 1 Monday, August 23, :52 PM. Part I of Change. The Mechanics. of Change

Chapter 1: Principles of Programming and Software Engineering

Mastering Data Abstraction or Get nit-picky on design advantages

Reliable programming

Programming in C++ Prof. Partha Pratim Das Department of Computer Science and Engineering Indian Institute of Technology, Kharagpur

Supporting Class / C++ Lecture Notes

Inheritance and Polymorphism in Java

Instantiation of Template class

QUIZ. What are 3 differences between C and C++ const variables?

OOP Design Conclusions and Variations

CS 370 The Pseudocode Programming Process D R. M I C H A E L J. R E A L E F A L L

Information Expert (or Expert)

How to approach a computational problem

Software Development. Modular Design and Algorithm Analysis

Review sheet for Final Exam (List of objectives for this course)

The Design Process. General Development Issues. C/C++ and OO Rules of Thumb. Home

It s possible to get your inbox to zero and keep it there, even if you get hundreds of s a day.

6.001 Notes: Section 17.5

Introduction to Design Patterns

MITOCW ocw f99-lec07_300k

5.6.1 The Special Variable this

CS112 Lecture: Working with Numbers

Review&Preview 1/23/15, 4:08:07 PM 1. 3rd edition - standardized, and standard library allows programmer to start from a higher level

Part X. Advanced C ++

How to Get Your Inbox to Zero Every Day

This wouldn t work without the previous declaration of X. This wouldn t work without the previous declaration of y

Think of drawing/diagramming editors. ECE450 Software Engineering II. The problem. The Composite pattern

Software Design and Analysis for Engineers

Short Notes of CS201

Lecture 13: more class, C++ memory management

6.096 Introduction to C++

Object-Oriented Programming

Object Oriented Programming COP3330 / CGS5409

CS201 - Introduction to Programming Glossary By

Programming Style and Optimisations - An Overview

Modellistica Medica. Maria Grazia Pia, INFN Genova. Scuola di Specializzazione in Fisica Sanitaria Genova Anno Accademico

Programming Languages. Streams Wrapup, Memoization, Type Systems, and Some Monty Python

C++ Inheritance and Encapsulation

Fast Introduction to Object Oriented Programming and C++

A function is a named piece of code that performs a specific task. Sometimes functions are called methods, procedures, or subroutines (like in LC-3).

Programming II. Modularity 2017/18

C++ Classes & Object Oriented Programming

Lecture 13: Object orientation. Object oriented programming. Introduction. Object oriented programming. OO and ADT:s. Introduction

Classes Nov 3, Ch

AXIOMS OF AN IMPERATIVE LANGUAGE PARTIAL CORRECTNESS WEAK AND STRONG CONDITIONS. THE AXIOM FOR nop

Absolute C++ Walter Savitch

1. Describe History of C++? 2. What is Dev. C++? 3. Why Use Dev. C++ instead of C++ DOS IDE?

6.001 Notes: Section 8.1

Introduction Of Classes ( OOPS )

CS112 Lecture: Variables, Expressions, Computation, Constants, Numeric Input-Output

QUIZ. Source:

6.001 Notes: Section 6.1

Computer Organization & Assembly Language Programming

Contents A Little C++

1: Introduction to Object (1)

CSE341: Programming Languages Lecture 19 Introduction to Ruby and OOP. Dan Grossman Winter 2013

The Design Patterns Matrix From Analysis to Implementation

Ch. 11: References & the Copy-Constructor. - continued -

Supplemental Handout: Exceptions CS 1070, Spring 2012 Thursday, 23 Feb 2012

C++ Style Guide. 1.0 General. 2.0 Visual Layout. 3.0 Indentation and Whitespace

G52CPP C++ Programming Lecture 9

P1_L3 Operating Systems Security Page 1

Part VII. Object-Oriented Programming. Philip Blakely (LSC) C++ Introduction 194 / 370

EMBEDDED SYSTEMS PROGRAMMING OO Basics

Ruby logistics. CSE341: Programming Languages Lecture 19 Introduction to Ruby and OOP. Ruby: Not our focus. Ruby: Our focus. A note on the homework

Introduction to Programming

Errors. Lecture 6. Hartmut Kaiser hkaiser/fall_2011/csc1254.html

Risk Management. I.T. Mock Interview Correction

Object-Oriented Principles and Practice / C++

Lambda Correctness and Usability Issues

Chapter 11. Categories of languages that support OOP: 1. OOP support is added to an existing language

Object-Oriented Thinking

05. SINGLETON PATTERN. One of a Kind Objects

C++ (Non for C Programmer) (BT307) 40 Hours

APPENDIX B. Fortran Hints

CSE 303: Concepts and Tools for Software Development

Ch. 12: Operator Overloading

Cosmology with python: Beginner to Advanced in one week. Tiago Batalha de Castro

Intro. Scheme Basics. scm> 5 5. scm>

377 Student Guide to C++

The Essence of Object Oriented Programming with Java and UML. Chapter 2. The Essence of Objects. What Is an Object-Oriented System?

Transcription:

Basic Class Design Goal of OOP: Reduce complexity of software development by keeping details, and especially changes to details, from spreading throughout the entire program. Actually, the same goal as software design concepts throughout: Originally, "structured programming" means using the information-hiding abilities of subroutines (functions) to help organize the code; a subroutine can be modified internally without requiring the calling code to change. Then, "modular programming" means breaking up the program into separate modules that can be developed and modified separately, and perhaps even re-used - like a library. A library is just a generally useful module. Definitions Client Code - the code that uses the classes under discussion. Coupling - code in one module depends on code in another module Change in one forces rewrite (horrible!), or recompile (annoying), of code in the other. Two of the Four key concepts of OOP Abstraction - responsibilities (interface) is different from implementation. Distinguish between interface and implementation. A class provides some services, takes on some responsibilities, that are defined by the public interface. How it works inside shouldn t matter. Client should be able to use just the public interface, and not care about the implementation. Encapsulation - guarantee responsibilities by protecting implementation from interference Developer of a class can guarantee behavior of a class only if the internals are protected from outside interference. Specifying private access for the internals puts a wall around the internals, making a clear distinction between which code the class developer is responsible for, and which code the client is not supposed to know or care about. Both are ways of decoupling the client code from the class implementation: Don't need to know about the implementation; Can't accidentally interfere with it or depend on it. A class is a software component that consists of some data and some procedures, coupled together, with an interface that abstracts and encapsulates the data and procedures, insulating the client from the details of implementation. Here, only concerned with Concrete" classes - no inheritance or polymorphism involved. Objects interact with each other, contain each other, refer to each other. 1

Main program causes initial objects to be created, delegates work to objects as needed. Two kinds of classes: Objects that are in the problem domain. Managing Media: Records, Collections Managing meeting schedule: Rooms, Meetings, Persons Banking: Customers, accounts, banks Objects that support the domain objects (useful to implement them). E.g. String, Ordered_list, std::map<>, etc Choose these to best get the work done. But you have to understand what the actual work is first! 2

Guidelines for Designing Individual Classes Designing Domain classes What kinds of objects are in the domain? Start with thinking about the objects, then group into classes. Which classes to they naturally belong to? What characterizes each domain object? Member variables - the data Member functions - operations on the data These are about the domain, not the implementation! How are different kinds of objects related to each other? Inclusion versus association - Part-of relation versus "using" or "interacts with" Do objects know about each other? one-way, or two-way? One-way: An object points to another object, but which does not point back Two-way: An object points to a second object which points back to the first Classes with two-way associations are: harder to work with, so do not use unless they represent the domain exactly have to ensure cross-pointers are valid, and no dangling pointers left. Relative lifetimes - Do they exist independently of each other? Design a class by choosing a clear set of responsibilities for it. Make classes responsible for working with their own data. Main code should delegate the work down into the classes that have the information. Deciding which class or module should be responsible for the work. Most general rule: who has the data? That component is probably the best one to do the work. Classes generally should be responsible for their data, and the work done with the data. If client code is doing the work, something is probably wrong - rethink it! If class responsibilities can't be made clear, then OOP might not be a good solution 3

Lots of problems work better in procedural programming than in OOP, so there is no need to force everything into the OO paradigm. Making this distinction is critical to understanding the difference between traditional procedural programming and OOP. But often, you just need to think about it more carefully. Anthropomorphize it - e.g. in P2, imagine a person playing the role of each class object. What is her job? How does she interacted with other objects? Beware of classes that do nothing more than hold data, like a C struct type. Sometimes you need simple holders of data - no associated functions or operations - if so, then it should not be a class. Or, you ve mis-assigned responsibilities - maybe this class should be doing the work, but some other component is doing it instead. Is it really a "Plain Old Data" object, like C struct, or did you overlook something? If it is a simple bundle of data, define it as a simple struct. If there are functions that operate on the data, maybe they should be member functions, and maybe these objects really are responsible for something. Beware of classes that are only supposed to get instantiated once during the program execution. Almost always, a class represents a kind of object that we will have many of, so a class that is supposed to correspond to only one object is suspicious. There are important design patterns in which having only one object is the concept. Used to clearly delimit responsibilities, separate concerns. But can be over-used - unless you are using one of the design pattern concepts, don t use a one-instance class - probably a bad idea. E.g. maybe there is only one of these objects because it is trying to do a whole bunch of things - like replace the main function. Maybe it is a god class - see below. 4

Some specific rules for class design - if breaking these, there might be something wrong with the design. Make all member variables private in each class Concept: Programmer of a class has to be able to guarantee that class will fulfill its responsibilities - do what he/she says it will do. encapsulation - making member data private- is the basic step that makes this guarantee possible - prevents other code from tampering with the data. No public member variables. Beware of get_ functions that return a non-const pointer or reference to a private member variable - breaks the encapsulation! Be careful if it is necessary to return a non-const reference or pointer to an item in a container member variable - even if client can't alter the container, might be able to alter the item in a way that violates design intent - or disorder the container! Resist the temptation to provide getters/setters for everything. Amounts to making the member variables public - why is this needed? Similar problem: providing getters that return iterators pointing into a container member variable if not const iterators, allows client code to modify private data regardless, client has to know an implementation detail - coupled to the choice of container for the member variable - why is this something the client needs to know? If you have to do this, something is probaby wrong with your design - why does somebody else have to put data in and pull data out of the object? why aren t the class s member functions doing the work? Put in the public interface only the functions and declarations that clients can meaningfully use. Functions that are only helpers for the implementation should be private. constants and enum types: should be private in the class if only the implementation needs them public in the class if the class client needs them at top level of header file ony if needed independently of any class - if so, why are they in the same header as the class declaration? Friend classes and functions are actually part of the public interface of the class, and belong with the class. 5

Friend class or function must be part of the same module or component. Most clear if declaration and implementation is in the same.h and.cpp files. A class developer should declare a class or functions to be a friends only if he/she/they are also responsible for, and have control over, that class or function. If class A uses class X for its internal work, and the client shouldn't have to see class X, then consider declaring class X as a private member of class A rather than have X be visible to the client with a friendship relation to A. Make member functions const if they do not modify the logical state of the object.\ Don t use mutable to fake a const member function in this course. Make a class fully responsible for initializing itself with constructor functions. It is error-prone and bad design if the client has to "stuff" initial data into the object. Take care that all member variables get a good initial value. Only supply these where necessary - if the member variable is a class type, the compiler will call its default constructor for you. Take care if the class design requires post-creation intialization - e.g. an initialization function called after construction e.g. a set_pointer() function to store the address of some other object in a pointer member variable. Sometimes required for designs in which objects point to each other Use initialize to nullptr in constructor, and then assertions to make sure pointer has been set to a real value before any code tries to use it. Do not write constructors, assignment operators, or destructors when the compiler-supplied ones will work correctly. Unnecessary code is simply places for bugs to hide! Especially when revisions are made! E,g, did you remember to fix the copy constructor when adding another member variable? Let the compiler do the work as much as possible - it will automatically respond to changes in the code. Explicitly decide whether the compiler-supplied special member functions (the destructor and the copy/move functions) are correct, and let the compiler supply them if so. Do not write code that the compiler will supply. Unnecessary code is an unnecessary source of bugs. 6

Try to follow the Rule of five or zero - either explicitly declare all five of the special member functions, or declare none of them and let the compiler supply them automatically. Declare here means to either declare and define your own version of the functions, or declare what you want the compiler to do with =default or =delete. If you have to write even one of these functions for some reason, explicitly declare the status of the rest of them to avoid confusion or possible undesired behavior. If you have to write your own destructor function to manage a resource (like memory), you almost certainly have to either write your own copy/move functions or tell the compiler not to supply them (with =delete). In writing a copy constructor, remember to copy over all member variables - a common error. If copy or move operations are not meaningful for a class, explicitly prevent the compiler from supplying them. For example, to enforce the concept that objects in the domain are unique. In C++11, disable compiler-supplied copy and move functions with the =delete syntax. 7

A couple of General DO NOT rules General Don t: Don t overengineer - Overengineering - a more complex solution than necessary. Often a result of anticipating future needs inappropriately. Yes, it is more complex, but if I do it this way, then in the future, it will be easier to do yada-yada. - but will this be needed? Problem: the code is harder to work with NOW, and you don t actually know whether you will need to do the future thing. YAGNI principle - you aren t going to need it. Wisdom of the gurus: If the code is a simple solution that is clear and well-designed, it will be easy to change it in the future if necessary. So design and code a current solution well, instead of making a mess trying to anticipate an unknown future. Another reason: Just getting complex without thinking through what the responsibilities of the classes really are - misdelegating, misassigning - the result is simply unnecesssarily complex. General Don t: Don t create heavy-weight, bloated, or "god" classes - prefer clear limited responsibilities. If a class does everything, it is probably a bad design. Either you have combined things that should be delegated to derived classes or peer classes, or you have misunderstood the domain. Example: In project 2 s restore function, the work of reading and interpreting the data file, and creating the right objects or relationships, was delegated to the Person/Meeting/ Room or Record/Collection classes, which do all the work, and just signal a problem if they can t. Only thing the main module knew is that Person/Record data comes first, then Room/Collection data. If a member variable was added to Person/Record, only the Person/Record class class would need to be changed. Contrast with a god-like main module that knows how Persons and Meetings and Rooms / Records and Collections are structured, and what the details of what data file looks like - it reads the data, validates it, creates objects, and stuffs the data into them from the outside while they just sit there passively. If a member variable is added to Person/Record, both the Person/Record declaration and the main module code would need to be changed. 8

Some Top-level Design suggestions Do the class design work at the level of the public interfaces, not the private implementations. Don t get bogged down in implementation details like I can do with this with a map container and a deque! Think only about what the class responsibilities are and what they do in their public interfaces: Class X is responsible for., class Y for. When an X object needs it calls the public member function of the appropriate Y object with as parameters, which returns Try writing pseudo code just for the interactions between class objects through their public interfaces. Keep this up until you can t stand it any more, only then make implementation choices and write the code. Continue design thinking until you have thought of at least two reasonable ways to solve each design problem. Reasonable here means not obviously stupid. Don t just jump on the first design you think of and hack it out. All designs are imperfect - they all involve trade-offs. They are good in some ways, bad in others. A good design is good in the most important ways, and bad in the less important ways. But there might be more than one good design - just different in the specific tradeoffs. You can t make an intelligent choice if you have only thought of one design - there could be another, better, simpler one. If the implementation turns out to be difficult or confusing to code, the reason might be a defective design - step back and rethink the design! Generally, good designs code easily, but bad designs tend to make such a mess of the code that it becomes harder and harder to complete it and debug it. Stop before it gets worse! It is impossible to anticipate every issue at the design stage - sometimes you do not discover important facts about the problem until you try to implement the design. If this happens, do not panic! Go back and rethink the design using what you now know about the problem. This should be relatively easy because the original design thinking is still helpful. But perhaps you made some assumptions or overlooked some issue; be prepared to revise the design, or consider a new one. Fixing a bad design is usually a better strategy than try to push through the messy implementation of a bad design. 9

Even if none of the previous code can be used, the coding of the new design goes faster once the design is clarified or corrected - you understand the problem better and are more clear about what has to be done. 10