120 likes | 218 Views
Good Design of Classes. Classes let us create Abstract Data Types Should be well aware of benefits Hide implementation details Localize changes Interface can be more informative More self-documenting Don’t have to pass data all over your program
E N D
Good Design of Classes • Classes let us create Abstract Data Types • Should be well aware of benefits • Hide implementation details • Localize changes • Interface can be more informative • More self-documenting • Don’t have to pass data all over your program • Work with real-world entities rather than low-level implementation structures • By now you should know all about building classes
Anything wrong with this class? class Program { public void InitializeStack(); public void PushCommand(Command c); public Command PopCommand(); public ShutdownCommandStack(); public void InitializeReportFormatting(); public void FormatReport(Report r); public void PrintReport(Report r); public void InitializeGlobalData(); public void ShutdownGlobalData(); … }
Anything wrong with this class? class EmployeeCensus { public void AddEmployee(Employee e); public void RemoveEmployee(Employee e); public Employee NextItemInList(); public Employee FirstItem(); public Employee LastItem(); … } Be sure you understand what abstraction the class is implementing
Designing Classes • Provide services in pairs with their opposites • E.g. Get/Set, Add/Remove • Move unrelated information to another class • Beware of erosion of the interface’s abstraction under modification class Employee { public string GetName(); public Address GetAddress(); … public boolean isJobActive(JobClass j); … public SqlQuery GetQueryToCreateEmployee(); … }
Designing Classes • Don’t expose member data in public • Don’t assume the class’s users know how to correctly use the class • // Initialize x, y and z to 1.0 because … • Avoid friend classes • Probably an indicator of classes that are too tightly coupled anyway • Favor read-time convenience to write-time convenience
Class Containment • Containment = Data Members • Variables should be “Has A” relationship • Implement “Has A” via inheritance as a last resort (i.e. using access to protected members) • Be critical of classes with more than about seven data members
Class Inheritance • Implements “Is A” relationship • Design and document for inheritance or prohibit it • Non-virtual in C++, final in Java, non-overridable in VB so can’t inherit from it • Move common interfaces, data, and behavior as high as possible in the inheritance tree • Be suspicious of classes with only one instance • Be suspicious of base classes with only one derived class • Be suspicious of classes that override a routine but do nothing in the derived routine • E.g. base Cat class with Scratch() but some cats are declawed and can’t scratch
Class Inheritance • Be suspicious of deep inheritance trees • Found to be significantly associated with increased fault rates • Prefer polymorphism to type checking with switch statements • But not in all cases, e.g.: switch (shapeType) { case Circle: DrawCircle(); break; case Square: DrawSquare(); break; … } switch (ui.command() ) { case Command_OpenFile: OpenFile(); break; case Command_Print: Print(); break; … }
Member Functions and Data • Keep the number of routines in a class as small as possible • Disallow implicitly generated member functions and operators you don’t want • E.g. to disallow =, you could define it and make it private • Minimize the number of different routines called by a class – fan out • One study found the number of faults was correlated with the total number of routines that were called from within the class • Minimize indirect routine calls to other classes • E.g. account.ContactPerson().GetDaytimeInfo().PhoneNumber(); • In general minimize the extent a class collaborates with other classes
Constructors • Initialize all member data in constructors if possible • Enforce the singleton property by using a private constructor public class MaxID { // Private members private static final MaxID m_instance = new MaxID(); // Private constructor private MaxID() { … } … // Public routines public static MaxID getInstance() { return m_instance; } } MaxID.getInstance() // Access reference to singleton
Constructors • For copy constructors or overloaded assignment operators, prefer deep copies to shallow copies • Even if it may be more inefficient, often leads to reference problems
Classes to Avoid • Avoid creating god classes • Omniscient classes that are all-knowing and all powerful • Consider whether that functionality might be better organized into those other classes • Eliminate irrelevant classes • E.g. class consisting only of data but no behavior; could be demoted to attribute of another class • Avoid classes named after verbs • Only behavior but no data could be a routine of another class