The Software development can be grouped in to three phase.
1.Meeting Customer Requirement
2.Applying OOAD Principles
3.Design Patterns

We need to create an app which does search of cars in garage.The search is going to take specification of cars as input and display the matching cars.

Phase 1:

Car.java

 public class Car {

	private String serialNumber;
	private String model;
	private String builder;
	private String price;
	private String type;	

	Car(String pserialNumber, String pmodel, String pbuilder, String pprice, String ptype)
	{
		serialNumber=pserialNumber;
		model=pmodel;
		builder=pbuilder;
		price=pprice;
		type=ptype;
	}

	public String getSerialNumber() {
		return serialNumber;
	}
	public void setSerialNumber(String serialNumber) {
		this.serialNumber = serialNumber;
	}
	public String getModel() {
		return model;
	}
	public void setModel(String model) {
		this.model = model;
	}
	public String getBuilder() {
		return builder;
	}
	public void setBuilder(String builder) {
		this.builder = builder;
	}
	public String getPrice() {
		return price;
	}
	public void setPrice(String price) {
		this.price = price;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}

	public enum Type {
		PETROL, DIESEL;

		public String toString() {

			switch (this) {
			case PETROL:
				return "petrol";

			case DIESEL:
				return "diesel";

			}
			return null;
		}
	}

	public enum Builder {
		FORD, HONDA, TOYOTA;

		public String toString() {
			switch (this) {
			case FORD:
				return "ford";

			case HONDA:
				return "honda";

			case TOYOTA:
				return "toyota";

			}

			return null;
		}

	}
}

Garage.java

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Garage {
	private List<Car> carList = new ArrayList<Car>();

	public void addCar(String pserialNumber, String pmodel, String pbuilder, String pprice, String ptype)
	{
		Car objCar = new Car(pserialNumber, pmodel, pbuilder, pprice, ptype);
		carList.add(objCar);
	}

	//The guitar will be returned only when all Search Criteria Match
	public List<Car> searchCar(Car searchCar)
	{
		List<Car> resultCarList = new ArrayList<Car>(); 

		for (Iterator iterator = carList.iterator(); iterator.hasNext();) {
			Car Car = (Car) iterator.next();

			if(!searchCar.getType().equals(Car.getType()))
				continue;

			if(!searchCar.getBuilder().equals(Car.getBuilder()))
				continue;

			resultCarList.add(Car);
		}

		return resultCarList;
	}

	public Car getCar(String SerialNo)
	{
		return null;
	}
}

SearchCar.java

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

public class SearchCar {
	public static void main(String[] args) throws IOException {
		Garage objGarage = new Garage();
		initializeCar(objGarage);

		Car searchCar = new Car("", "A1", Car.Builder.FORD.toString(), "",
				Car.Type.PETROL.toString());
        List<Car> searchResult  =  objGarage.searchCar(searchCar);

        if(searchResult != null)
        {
        	System.out.println("Search Result");

        	System.out.println("-------------------------------");

			for (Iterator iterator = searchResult.iterator(); iterator.hasNext();) {

				Car Car = (Car) iterator.next();

	        	System.out.println("Model : "+ Car.getModel());
	        	System.out.println("Builder : "+ Car.getBuilder());
	        	System.out.println("Type : "+ Car.getType());
	        	System.out.println("-------------------------------");
			}
        }else
        {
        	System.out.println("Sorry! We are unable to Find Car...");
        }
	}

	public static void initializeCar(Garage pobjGarage) {
		//pserialNumber, pmodel, pbuilder, pprice, ptype
		pobjGarage.addCar("", "Mustang", Car.Builder.FORD.toString(), "", Car.Type.PETROL.toString());
		pobjGarage.addCar("", "Corolla", Car.Builder.TOYOTA.toString(), "", Car.Type.DIESEL.toString());
		pobjGarage.addCar("", "Endevadour", Car.Builder.FORD.toString(), "", Car.Type.PETROL.toString());
		pobjGarage.addCar("", "Civic", Car.Builder.HONDA.toString(), "", Car.Type.PETROL.toString());
	}
}

Points to Note:

  1. When specifications contains less number of search criteria like Fuel Type which can be either petrol or diesel use ENUM.By doing this we are avoiding String comparison and other overheads like converting to lowercase, uppercase before comparison
  2. The searchCar method in Garage will return Cars only when all specs matches the car in the garage.

Phase 2
Object Orientation

  1. Objects should do what their name Indicate
  2. Each Object should represent a Single Concept
  3. Unused properties are dead give away

In the above code the Search criteria used can be split separately.
This includes Type, Model and Builder.
The Price and Serial No are not moved to new class since they are unique.

CarSpec.java

public class CarSpec {

	private String model;
	private String builder;
	private String type;

	public CarSpec(String pbuilder, String pmodel,String ptype){
		model=pmodel;
		builder=pbuilder;
		type=ptype;
	}

	public String getModel() {
		return model;
	}
	public void setModel(String model) {
		this.model = model;
	}
	public String getBuilder() {
		return builder;
	}
	public void setBuilder(String builder) {
		this.builder = builder;
	}

	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
}

Now the car class is going to be replaced with CarSpec variable as property.


public class Car {

	private String serialNumber;
	private String price;
	private CarSpec carSpecification;

	Car(String pserialNumber, String pprice, CarSpec pcarSpec)
	{
		serialNumber=pserialNumber;
		price=pprice;
		carSpecification = pcarSpec;
	}

	public String getSerialNumber() {
		return serialNumber;
	}
	public void setSerialNumber(String serialNumber) {
		this.serialNumber = serialNumber;
	}

	public String getPrice() {
		return price;
	}
	public void setPrice(String price) {
		this.price = price;
	}

	public CarSpec getCarSpecification() {
		return carSpecification;
	}

	public void setCarSpecification(CarSpec carSpecification) {
		this.carSpecification = carSpecification;
	}

	public CarSpec getCarSpec(){
		return carSpecification;
	}
}

Since the Specification of the car are moved separately they can be used for both searching and storing car details.

Now the searchCar() method in Garage.java should be allowed to take car Specification as argument instead of whole car object which contains redundant Price and Serial No which are unique.

Garage.java

 import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Garage {
	private List<Car> carList = new ArrayList<Car>();

	public void addCar(String pserialNumber, String pprice, CarSpec pcarSpec)
	{
		Car objCar = new Car(pserialNumber, pprice, pcarSpec);
		carList.add(objCar);
	}

	//The guitar will be returned only when all Search Criteria Match
	public List<Car> searchCar(CarSpec searchCarSpec)
	{
		List<Car> resultCarList = new ArrayList<Car>(); 

		for (Iterator iterator = carList.iterator(); iterator.hasNext();) {
			Car objCar = (Car) iterator.next();

			CarSpec objCarSpec = objCar.getCarSpec();

			if(!objCarSpec.getBuilder().equals(searchCarSpec.getBuilder()))
			 continue;

			if(!objCarSpec.getType().equals(searchCarSpec.getType()))
			  continue;

			resultCarList.add(objCar);
		}

		return resultCarList;
	}
}

Searchcar.java

public class SearchCar {
	public static void main(String[] args) throws IOException {
		Garage objGarage = new Garage();
		initializeCar(objGarage);

		CarSpec searchCar = new CarSpec(Builder.FORD.toString(), "", Type.PETROL.toString());
        List<Car> searchResult  =  objGarage.searchCar(searchCar);

        if(searchResult != null)
        {
        	System.out.println("Search Result");

        	System.out.println("-------------------------------");

			for (Iterator iterator = searchResult.iterator(); iterator.hasNext();) {

				Car objCar = (Car) iterator.next();
				CarSpec objSpec = objCar.getCarSpec();

				System.out.println("Car Name : "+ objCar.getSerialNumber());
				System.out.println("Car Name : "+ objCar.getPrice());
	        	System.out.println("Model : "+ objSpec.getModel());
	        	System.out.println("Builder : "+ objSpec.getBuilder());
	        	System.out.println("Type : "+ objSpec.getType());
	        	System.out.println("-------------------------------");
			}
        }else
        {
        	System.out.println("Sorry! We are unable to Find Car...");
        }
	}

	public static void initializeCar(Garage pobjGarage) {
		//pserialNumber, pmodel, pbuilder, pprice, ptype
		pobjGarage.addCar("101", "Mustang", new CarSpec(Builder.FORD.toString(), "3200", Type.PETROL.toString()));
		pobjGarage.addCar("201", "Corolla", new CarSpec(Builder.TOYOTA.toString(), "3500", Type.DIESEL.toString()));
		pobjGarage.addCar("102", "Endevadour", new CarSpec(Builder.FORD.toString(), "5200", Type.PETROL.toString()));
		pobjGarage.addCar("301", "Civic", new CarSpec(Builder.HONDA.toString(), "3000", Type.PETROL.toString()));
	}
}

Now we are going to move the Search Car Code from Garage.java to CarSpec.java.By doing this we are delegating the job to highly coherent class.
In case any code to be added in future the changes to be done are only confined within this class.We are also going to perform object to object comparison.

Garage.java

.
.
.

public List<Car> searchCar(CarSpec searchCarSpec)
	{
		List<Car> resultCarList = new ArrayList<Car>(); 

		for (Iterator iterator = carList.iterator(); iterator.hasNext();) {
			Car objCar = (Car) iterator.next();

			CarSpec objCarSpec = objCar.getCarSpec();

			if(objCarSpec.findMatchingCar(searchCarSpec))
			 resultCarList.add(objCar);
		}

		return resultCarList;
	}

.
.
.

we are calling findMatchingCar method of CarSpec.java instead of doing the comparison in the same class.

CarSpec.java

.
.
.
public boolean findMatchingCar(CarSpec objCarsPEC)
	{
		if(builder !=  objCarsPEC.getBuilder())
		 return false;

		if(type !=  objCarsPEC.getType())
		 return false;

		return true;
	}
.
.
.

————————————————————————————————

Things Learned

  1. Objects should do what their name indicate and should represent a single concept(high cohesion).
    By Moving the specifications on which the search is made into new class CarSpec.java instead of keeping them in Car.java we have achieved high cohesion.
  2. By Delegating the search functionality to class CarSpec.java we have achieved flexibility. In case there
    is new property say four wheel drive or power window added as search criteria the only class file to be changed is CarSpec.java
  3. High cohesion achieved is also evident from the fact that we can do object to object comparing to match the search criteria. findMatchingCar() Method is doing the same.
  4. If object is used with null value or no value you are using object for more than one job.Simple example is doing a null check on a object property which is not a good business code implementation