You are on page 1of 16

11/12/12

OOP.htm

Why coding standards are important in OOP?


Writing code for others, not for you. Greater consistency. Easier to understand. Easier to maintain. Reduces the overall cost of the application. Code for people, not for machine.

GRASP in a Nutshell
Generalized Responsibility Assignment Software Patterns This pattern outline few best practices that need to be considered before writing coding The core intention of the practice is 3R (Roles, Responsibility and Reusability) Information Expert: A class should only have the information necessary to fulfill its Responsibility. Creator: Responsibility of creation of instance should be defined properly. Low Coupling: Assign a responsibility so that coupling remains low. High Cohesion: Assign a responsibility so that cohesion remains high. Controller: Assign the responsibility for receiving and handling a system event message to a class that is either: Representative of the entire subsystem (e.g. a Faade Controller). These classes can be the main interface classes. (MVC) Polymorphism: When related behaviours vary by type (class), assign polymorphically to the specialization classes. In simple words, use Overloading. the responsibility

Dont Talk to Strangers: Do not couple two objects that have no obvious need to communicate. In simple, when you are about to assign a responsibility, ask yourself the following question: Is this responsibility related to the other responsibilities of this class? If not, there is likely a need to assign the responsibility to another class. This may prompt you to create a new class if other responsibilities exist that are similar/related to this one.

Standards for a CLASS


1/16

11/12/12

OOP.htm

A class is any uniquely identified abstraction - that is, a model - of a set of logically related instances that share the same or similar characteristics. Following are the key points we need to think about before writing a class.

Class Name The name of the class should be NOUN and it should explain the abstract level
purpose and the responsibility of the class. Ex. HashMap The name says this class hold a map [x y] (literal meaning) and it uses some hashing principles for management. Names like AddEmployee, CreateDatabase etc should not be used. In such cases write classes like Employee [with add method] and DatabaseManager [with create method]

Packing a class Since classes are uniquely identified entities, it should be packed in respective
packages. Packages should not contain irrelevant classes. Ex. com.ustr.myapp.dao is a package which contains all Data Access Object. This package should not contain any non-dao classes like ServiceUtil, MyAppException Standard: com.<companyid>.[corporate].appname.<sub packages>

Class Scope Scope explains the visibility of the class. Provide appropriate visibility for each class.

Ex. You have a Factory class FileWriterFactory which takes the responsibility of creating the FileWriters, the scope should be defined as shown in below diagram

ADDING MEMBERS AND FUNCTIONS (ACTION OR MESSAGES) TO A CLASS Members: Collection of properties which define a class structure. All the members should have
concrete relationship with the class structure. In simple, the class members should be relevant to the class. Ex. Class ConnectionManager can have members like List of Connections, connection parameters. Resultset, Statement, List of Employee should not be the part of members. These types of members should be used only within the appropriate methods. There is a common practice like, whenever a variable is used within more than one method, that variable is declared as class-member. We should not share the members unless it is meant for. Note: 1. In case if you need to share the members between methods, create the member in a method and pass it to next method. 2. Dont use a variable for multiple purposes. Re-use of variables are not recommended. To avoid f ile:///C:/Users/rrajasen/Documents/OOP.htm 2/16 this, it is always recommended to provide meaningful names for variables.

11/12/12

OOP.htm

this, it is always recommended to provide meaningful names for variables. Naming a Member: Member names should be self explanatory. Sometimes the usage can be identified by its type also. But it is always recommended to use meaningful names. Ex. connectionList List of connection isConnectionClosed says whether a connection is closed. Note: Do not use variables like i, j, flag, status etc. Instead use rowIndex, processStatus, isFileExist etc Member Types: Use the appropriate type for the members. The type is used to identify the data value type stored. It is recommended (depends on usage) that appropriate Generic type should be used for maintainability and scalability. Ex. Use Map colorMap instead of HashMap colorMap In case if you are sure about the data type and if that never change in future, than it is always better to use appropriate type (non-generic). Ex. Use Double empSalary instead of Number empSalary. Use LinkedHashSet empDetails instead of Set empDetails. [Note: in the second example, we cant assign any other implementations of Set. This is not recommended when you use your own collections implementations or frameworks] When you deal with primitive type, use the possible lowest data type. Ex: use short age instead of int age. If you are storing 0 or 1 use boolean always. Scope of a member: The scope refers to the visibility of the member. It is always recommended to provide the low visibility (private) unless demanded. The following table shows the visibility and the purpose.

Visibility public private default protected

Purpose Can be accessed by anyone Can accessed only within the component Package level access Used for inheritance

Usage Use only for shared constants Recommended to use always

Only if the member is inherited.


3/16

f ile:///C:/Users/rrajasen/Documents/OOP.htm

11/12/12

OOP.htm

Also in case if you need to give public access to a member, it is recommended to do using a getter/setter method. private int age; public int getAge(){ //Can provide security check/condition return age; } public void setAge(int age){ //Can provide security check/condition this.age = age; } Providing public access to members may corrupt the member. Also note providing both getter and setter for all the members are not recommended. They should be provides only as per the requirement. See the below example. public class FileReader { private int numOfFilesRead = 0; public void readFile(File f) { numOfFilesRead++; } public int getNumOfFilesRead(){ return this.numOfFilesRead; }

Note that the member numOfFilesRead is used for internal manipulation. So providing a setter or public access may corrupt the value. Creation of members: Primitive Types: All the primitive type members can be created in constructors itself. It can be done either by assigning default values or parameterized value or both. public class Employee { private int empID; private String name; private String project; public Employee (String name) { empID = EmpIDGenerator.createID(); this.name = name; project = Project.POOL; }
f ile:///C:/Users/rrajasen/Documents/OOP.htm

public void setProject(String project){

4/16

public void setProject(String project){ this.project = project; }

The setter method helps in injecting new projects for the Employee. Non-Primitive Types: Before explaining creation of non-primitive types (Object), we need to know what relationships between classes are. Relationship Relationship tells how two classes are related. Following are some of the relationships which need to be applied: 1. Dependency 2. Association Dependency: Is a semantic relationship between two components in which a change to the independent thing may affect the semantics of the dependent things. This is the weakest relationship we can have. Figure 1 shows the dependency relationship.

Figure 1: Dependency relationship

In the above example HTMLWriter is depended on HTMLHelper just for writing HTML Characters, using getChar() method. So if there is a change in getChar implementation, then the meaning (semantic) of HTMLWriter.writemethod will also change, but if there is any change in any other functions in HTMLHelper, it never affect the HTMLWriter Class, which is called Dependency relationship. In simple only the functionality will change and not the structure of the Caller class. Association: Is a structural relationship that describes a set of links, a link being a connection among objects.

11/12/12

OOP.htm

Figure 2: Association relationship

In the above example, the FileWriter is fully dependent on File component. Here it is always good to use associate instead of dependent. The structure of the FileWriter component is explained using its associated members. So whenever the data type of fileToWrite is changed or File class is changed, the structure of FileWriter will also be changed. CAUTION: Change in structure of already designed (finalized) component is not a best approach in Object Orientated Development. Where to create dependent object for dependency relationship? The objects should be created only whenever needed. In general, it should be created only within the methods. In case if you need to share such object create it and pass it as argument to other methods (private). HTMLWriter { public write(ch) { HTMLHelper helper = new HTMLHelper(); print(helper.getChar()); doSomething(helper); } private doSomething(HTMLHelper helper){ . } }

Where to create dependent object for association relationship? The object should be created or initialized in the constructor itself. If in case the object is dependent, it can be passed as parameters for constructors or use setter methods for assignment (dependency injection). If the association is very strong (composition) then the object creation should be created in constructor. Note: As per programming concepts, the responsibility of destroying an object is given to the component which created it [in non-trust relationship]. So be caution when you share the associated objects with outside components (using getter methods). It is recommended that for Objects, it is always good to return the cloned version of the object. For collections, either pass the Collections.unmodifiableCollection collections or its Iterator.

Example of Associate Object Creation

HTMLWriter { File fileToWrite; HTMLWriter(String filename){ fileToWrite = new File(filename) } HTMLWriter(File file){
f ile:///C:/Users/rrajasen/Documents/OOP.htm

this.fileToWrite = file

6/16

11/12/12

OOP.htm

this.fileToWrite = file } //NO SETTER IS USED write(ch){ }

Note: In case if the associate object is initialized by non-constructor methods (like setter, initialize), then it is always recommended to check for existence before usage in public methods. write(ch){ if(filetoWrite != null) . } Destroying associated objects: It is always recommended to provide methods like close, destroy, finalize etc for destroying strongest associated references. Case study for Associated reference Creation/destroy

TIP TO THINK: Think about making conn=null in Connection Manager instead of closing the connection. The object inside JVM will be released but the reference to the db server will not be release [dead connection]. Also note who creates the connection and who destroys it. It should be done within the component itself, because the connection to DB Server is strongly associated with the components. Sharing Members: In most of the cases we may need to share members across multiple instances of same class or between classes. The sharing can be done using static keyword in Java. It is not recommended to share a modifiable member by providing public access. For such cases use private static and provide getter/setters. public static int MAX_CONNECTION = 10; //Not recommended instead use private static int MAX_CONN = 10; public static int getMaxConnections(){return this.MAX_CONN}
f ile:///C:/Users/rrajasen/Documents/OOP.htm 7/16

11/12/12

OOP.htm

Note: Use static only when sharing public constants. public static final int MAX_CONNECTION = 10;

Methods: As per OOAD methods are the actions or messages that can be handled by a particular
component. Using irrelevant methods in a class may change the meaning of that class. Ex. We should not have public read() method for writer classes. Points to be asked before declaring an action/method in a component, 1. Is this action part of the component? 2. What does this action do? 3. What should be the appropriate name of the action? Note: The method name with its parameters should give an abstract of what the action is. Ex. Connection getConnection(user,passwd) 4. Implementation should not exceed 50 to 100 lines. 5. Use private methods where-ever necessary. Types of methods: private: Can have any number of private methods (not complex). These methods are used to support and provide separate implementation for public/protected methods. Using private method will help readability and reusability. public: Use only limited number of public methods. Each public method should explain various actions in that component. While writing public methods all the inputs should be validated before processing. More details will be given later. protected: Methods that need to be inherited. Be caution here for security. There is a high chance to override non-private methods. Following options can be given with above method types. final: Recommended. Make all the methods and its parameter final, unless demanded by your application or used for inheritance. shared (static): These are members related to class and not to objects. They are created for doing some common utility or share data. It is recommended to provide less number of static methods in normal classes. Example public final boolean copy(final File srcFile, final File destFolder){ boolean copyStatus = false; if(validateInput(srcFile,destFolder)){ if(!destFolder.exist()) destFolder.mkdir(); File destFile = new File(destFolder,getFileName(srcFile); copyStatus = copyFile(srcFile,destFile);

} return copyStatus;

f ile:///C:/Users/rrajasen/Documents/OOP.htm

8/16

11/12/12

OOP.htm

private boolean validateInput(File srcFile,File destFolder){ boolean result = false; boolean isNull = (srcFile == null) && (destFolder == null); //Can add more conditions or call other validate methods. //finally result can be logical AND of all validations' } result = isNull;

private boolean copyFile(File srcFile,File destFile){ .... }

TIPS: Public methods should be at least (75%) readable by non-technical persons. Use private methods wherever possible. Use less inline documentation for explaining the logic. Public methods should be simple. Complex logics within the public methods can be moved to private method. In simple, anyone should understand the logic of a public method in less than 30 seconds. For reusability write more generic methods.

Logging
It is not recommended to use System.out or any console based output statements for logging purpose. As a standard it is always recommended to use Apache Log4j.

Levels in Log4j
DEBUG: Used only for development purpose. log.debug(Value of index + index); WARN: Used when you need to inform the users about the information as WARNING. log.warn(Dest folder is null, creating the folder); INFO: Just an information like input parameter values. log.info(Inside copyFile method); ERROR: Normally used with exception. Used when some condition is false; log.error(Number of threads exceeds the limit); log.error(Error while copying,ioexception);

Documentation
f ile:///C:/Users/rrajasen/Documents/OOP.htm 9/16

11/12/12

OOP.htm

Even though the class name, member name, method name etc are self-explanatory, it is always recommended to provide appropriate documentation (javadoc) where ever possible. Class level, Method Level documentation should be provided for all classes and methods. Refer javadoc documentation for more parameters about Java Documentation.

Exception Handling
Exceptions are not the errors, they are just an expected/un-expected situation occur in a program which can be handled properly. To know better about handling exception, consider the following scenario. You were asked by your manager to attend a very important meeting. This meeting happens regularly (at least 4 times a month). Workflow 1: Start from home Check for Car's Condition if not conditioned fix it Start the car Driving in progress reached at time and attend the meeting Workflow 2: Start from home check for Car's Condition if not conditioned fix it start the car driving in progress Heavy traffic Take deviation driving in progress Flat tire Replaced flatted tire driving in progress Your were late by 10 mins Inform your manager about the meeting and go back The pseudo code can be something like, travelAndAttendMeeting() throws DrivingException,UnableToAttendException{ boolean needToFillGas = false; boolean isCarConditioned = false; try{ isCarConditioned = checkForCarCondition(); }catch(LimittedGasException e){ //Checked Exception needToFillGas = true; isCarConditioned = true; }catch(NoGasException e){ //Checked Exception return; }
f ile:///C:/Users/rrajasen/Documents/OOP.htm 10/16

11/12/12

OOP.htm

if(!isCarConditioned) fixTheProblem() car.start(); Route r = getRoute(); try{ drive(r); }catch(HeavyTrafficeException e){ //Runtime Exception r = getNewRoute(); }catch(DrivingException e){ if(e instanceof FlatTiredException){ replaceTyre(); } else { //Log it throw e; } } try{ drive(r); //Need not check for exception (assumption: No traffic) }catch(DrivingException e){ if(e instanceof FlatTiredException){ replaceTyre(); } else { //Log it throw e; } } } attendMeeting();

Let us now look into various type exceptions provided by Java and how do we handle exceptions.

Checked or Compiled-Time exception: I prefer to use the term checked exception rather than

compiled time. Checked exceptions are the exceptional cases we need to check before planning. This happens while planning. In the above code LimittedGasException is a checked exception, which means this exception should be properly handled (checked) before the actual execution of the process happens. Programmatically this exception is checked by the compiler during compilation process. For convenience, Java compiler helps you in remembering this, in case you forget to put trycatch. Hence, it is also called compile-time exceptions.

Unchecked-Runtime Exceptions: These are exceptions happens during the process. Some of
these exceptions can be handled then and there; others need to inform the caller. See this, try{

drive(r); }catch(DrivingException e){ if(e instanceof FlatTiredException){ replaceTyre(); } else { //Log it


f ile:///C:/Users/rrajasen/Documents/OOP.htm 11/16

11/12/12

OOP.htm

throw e;

Since this person is able to handle FlatTiredException, he calls replaceTyre and fixed it, in other case he informs the caller.

HOW TO DECIDE WHETHER TO CREATE A CHECKED OR UNCHECK EXCEPTION


You can use the following thumb rule: If you need others to check the exception before execution (Compile time) then create Checked Exception and throw it from the method. Ex. LimitedGasException, FileNotFoundException If an error caused during the process (Runtime) and if you need to inform the caller, create UnChecked Exception and throw it from the method. Ex. DrivingException, ArrayIndexOutOfBoundsException To make it clear, take the array index out of range exception, this is caused only if the accessing index is greater than array size. Since this index is created in runtime, we cant always check this during compile time. Note: Runtime exceptions can be known only during the execution process. This may caused due to some logical errors. Be caution while catching the Run-time exception. One such error is NullPointerException.

TIPS

Tip1: Do not throw implementation or logic specific exceptions In our case, we should not throw LimittedGasException, because that is the part of implementation. Whereas DrivingException, UnableToAttendException are the part of functionality. Another example, compress(InputStream in, OutputStream out){ //read from instream //store it to a temporary location (for some reason) //For that you have opened a FileOutputStream, which throws FileNotFoundException. //Handle this exception here & DO NOT THROW //compress //Write to out stream } Tip 2: Logging the exception Exceptions should be logged in the place where it is raised (originated). Then you can either handle it there or re-throw the exception. Ex. Web Business DAO Exception Raised here In this case log the exception in DAO Layer.
f ile:///C:/Users/rrajasen/Documents/OOP.htm

Tip 3: Do not throw layer specific exceptions outside that layer

12/16

11/12/12

OOP.htm

Tip 3: Do not throw layer specific exceptions outside that layer

Types of classes

(Util, Helper, Implementation, Data (VO/DTO))

Util Classes: These classes act as a utility, which normally contains independent utility methods.
Following are the rules that need to be followed when writing an Util Class. 1. Class should be static All the methods in the class should be static. 2. Should be non-instantiated class Use final with private constructor. 3. Should not have any relationship or dependency with any other application related classes 4. Should not expose any shared (static) members. Ex. public final class WebUtil{ private WebUtil() { } public static String convertToHTML(String text){ } public static void encrypt(PrintWriter writer, String text){ } }

You can write generic UTIL class or Application Specific UTIL class. Considering reusability it is not recommended to combine it together for reusability.

Helper Classes: These are the classes which helps the classes to do some extra functionality. This
class is more specific to Applications or Functionality. This class is more similar to Util. Ex. If you have a view which displays all the available Projects in the database, it is always preferred to write a Helper instead of Util.
f ile:///C:/Users/rrajasen/Documents/OOP.htm 13/16

11/12/12

OOP.htm

EmployeeView { List<Project> getProjects(){ //DO NOT DIRECTLY ACCESS DAO FROM HERE return ProjectHelper.getProjects(); }

Note: All the rules used for creating Util class is applied here also.

Implementation classes: Classes in which actual implementation is programmed. It is a best


practice to follow an interface-oriented programming instead of concrete classes. This helps in decoupling the dependency between layers and implementation. Ex. interface Compression { encrypt () decrypt () } public class CompressionImpl implements Compression { } Note: At any point of time we can change the implementation classes with different algorithms, without affecting the caller. Use Factory pattern to construct such implementation classes.

Data Holding Classes

(POJOs Value Objects or Data Transfer Objects) These classes holds data for processing. The main differentiation between these classes and others are these classes will have data and logic related to the data, whereas other classes use these objects for its functionalities in an application. Note: These are the classes we normally take into consideration while we learn basics of OOPs (Classes and Objects). Also these objects are re-usable components, so no business logics or function specific annotations are allowed. Following are the rules that need to be followed. 1. At least one level of this class should be insatiable. 2. Proper constructors should be provided. 3. Necessary setters and getters need to be provided. 4. Need to override hashcode, equals and toString. 5. If the objects are meant for comparing or sorting, implementation of Comparable is recommended. 6. Always give public access to data members through public getter methods. 7. Use Cloneable interface with caution. Refer related documents on POJO, VO and DTO for the variations.
f ile:///C:/Users/rrajasen/Documents/OOP.htm 14/16

11/12/12

OOP.htm

Ex. public class Employee implements Comparable { private String empid; private String name; private float salary; public Employee (String name, float salary){ this.name = name; this.empid = EmployeeHelper.getNextEmployeeID(); this.salary = salary; } public void modifySalary (float salary) { //Dont use any business logic here //Logic should be used outside and call this //method using the final value. if(hasPermission()){ this.salary += salary; } } //Override hashCode, equals, toString and compareTo //Refer to API Reference (http://java.sun.com/j2se/1.4.2/docs/api/). }

Overriding hashCode/equals/toString
It is important that we need to override all these three methods (even it is not used). To know more about the purpose and implementation of these methods refer following links. Example Reference: http://www.geocities.com/technofundo/tech/java/equalhash.html http://www.javapractices.com/topic/TopicAction.do?Id=28 http://www.javapractices.com/topic/TopicAction.do?Id=55

General Tips
1. It is not recommended to return USER FRIENDLY messages from Service layer. Instead return a status code and UI will use some builder to prepare the message

f ile:///C:/Users/rrajasen/Documents/OOP.htm

15/16

11/12/12

OOP.htm

2. Re-visit (you will know how simpler your code is) and try to optimize to the maximum you can. 3. Main aspects you need to look far are 3R (Responsibility, Reusability and Readability)

In general create class using KISS rule.

Keep It Simple, Stupid

f ile:///C:/Users/rrajasen/Documents/OOP.htm

You might also like