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 Façade Controller).
These classes can be the main interface
classes. (MVC)
Polymorphism: When related behaviours vary
by type (class), assign the responsibility polymorphically to the
specialization classes. In simple words, use Overloading.
Don’t 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.
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
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.
A class is a unique structure that defines the attribute data and the methods or functions that operate on that data.
A class is a unique structure that defines the attribute data and the methods or functions that operate on that data.
As per UML Class is Any uniquely identified abstraction that models a single thing, where the term object is synonymous with instance.Classes have attributes and methods.
(Define a "Class" without using the word "Object")
(Define a "Class" without using the word "Object")
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. Don’t use a variable
for multiple purposes. Re-use of variables are not recommended. To avoid
this, it is always recommended to provide meaningful names for variables.
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
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…
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 can’t 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.
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
|
Purpose
|
Usage
|
public
|
Can be accessed by anyone
|
Use only for shared constants
|
private
|
Can accessed only within the component
|
Recommended to use always
|
default
|
Package level access
|
|
protected
|
Used for inheritance
|
Only if the member is inherited.
|
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.
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.
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.
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;
}
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.
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.write method 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.
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.
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){
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
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}
instead use
private static int MAX_CONN = 10;
public static int getMaxConnections(){return this.MAX_CONN}
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.
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();
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;
}
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){ .... }
copyStatus = copyFile(srcFile,destFile);
}
return copyStatus;
}
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.
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
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.
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 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
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;
}
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.
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;
}
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 try…catch. 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
throw e;
}
}
try{
drive(r);
}catch(DrivingException e){
if(e instanceof FlatTiredException){
replaceTyre();
} else {
//Log it
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 ‘Un-Checked 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 can’t 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.
Tip 3: Do not throw layer specific exceptions outside that layer
Ex.
Web à Business à DAO à Exception Raised here
In this case ‘log’ the exception in DAO Layer.
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.
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.
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.
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.
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.
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.
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
(POJO’s Value Object’s or Data Transfer Objects)
(POJO’s Value Object’s or Data Transfer Objects)
These classes hold’s 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.
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) {
//Don’t 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/).
}
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.
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) {
//Don’t 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:
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
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
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
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”
References
http://www.javapractices.com/home/HomeAction.do
http://www.amazon.com/gp/reader/0201310058/ref=sib_dp_pt#reader-link
http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html
http://java.sun.com/docs/codeconv
http://jcsc.sourceforge.net
http://www.mindview.net/Books/TIJ - Good Book (Thinking in Java)
http://www.javaperformancetuning.com/
http://www.javapractices.com/home/HomeAction.do
http://www.amazon.com/gp/reader/0201310058/ref=sib_dp_pt#reader-link
http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html
http://java.sun.com/docs/codeconv
http://jcsc.sourceforge.net
http://www.mindview.net/Books/TIJ - Good Book (Thinking in Java)
http://www.javaperformancetuning.com/
---A good developer knows
that there is more to development than programming---