DesignPattern : Strategy

1. Introduction

    Look at the example below:

    We want to sort an array of integer.

    1) Test case

package edu.xmu.designPattern.DesignPattern_Strategy;

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

import org.junit.Before;
import org.junit.Test;

public class StrategyTest
{
	private List<Integer> dataList = new ArrayList<Integer>();

	@Before
	public void setUp()
	{
		dataList.add(1);
		dataList.add(0);
		dataList.add(2);
		dataList.add(-11);
		dataList.add(100);
	}

	@Test
	public void test()
	{
		DataSorter.ascSort(dataList);

		for (Integer data : dataList)
		{
			System.out.println(data + ", ");
		}
		System.out.println("====================================");
		
		DataSorter.descSort(dataList);

		for (Integer data : dataList)
		{
			System.out.println(data + ", ");
		}
	}
}

   2) Core function

package edu.xmu.designPattern.DesignPattern_Strategy;

import java.util.List;

public class DataSorter
{
	public static void ascSort(List<Integer> dataList)
	{
		// bubble sort
		for (int i = 0; i < dataList.size(); i++)
		{
			for (int j = 0; j < dataList.size() - i - 1; j++)
			{
				if (dataList.get(j) > dataList.get(j + 1))
				{
					swap(dataList, j, j + 1);
				}

			}
		}
	}
	private static void swap(List<Integer> dataList, int i, int j)
	{
		int temp = dataList.get(i);
		dataList.set(i, dataList.get(j));
		dataList.set(j, temp);
	}

	public static void descSort(List<Integer> dataList)
	{
		// bubble  sort
		for (int i = 0; i < dataList.size(); i++)
		{
			for (int j = 0; j < dataList.size() - i - 1; j++)
			{
				if (dataList.get(j) < dataList.get(j + 1))
				{
					swap(dataList, j, j + 1);
				}

			}
		}
	}
}

   The solution above is quite simple and easy to understand.

   But what if we want to sort an array contains a more complex data type, how should we implements?

2. Example as below:

    1) Bean we want to sort

package edu.xmu.designPattern.DesignPattern_Strategy;

public class Cat
{
	private int height;
	private int weight;

	public int getHeight()
	{
		return height;
	}

	public void setHeight(int height)
	{
		this.height = height;
	}

	public int getWeight()
	{
		return weight;
	}

	public void setWeight(int weight)
	{
		this.weight = weight;
	}

}

   2) The core function (Here we are using the height of cat as comparision element)

package edu.xmu.designPattern.DesignPattern_Strategy;

import java.util.List;

public class DataSorter
{
	public static void ascSort(List<Cat> dataList)
	{
		// bubble sort
		for (int i = 0; i < dataList.size(); i++)
		{
			for (int j = 0; j < dataList.size() - i - 1; j++)
			{
				if (dataList.get(j).getHeight() > dataList.get(j + 1)
						.getHeight())
				{
					swap(dataList, j, j + 1);
				}

			}
		}
	}

	private static void swap(List<Cat> dataList, int i, int j)
	{
		Cat temp = dataList.get(i);
		dataList.set(i, dataList.get(j));
		dataList.set(j, temp);
	}

	public static void descSort(List<Cat> dataList)
	{
		// bubble sort
		for (int i = 0; i < dataList.size(); i++)
		{
			for (int j = 0; j < dataList.size() - i - 1; j++)
			{
				if (dataList.get(j).getHeight() < dataList.get(j + 1)
						.getHeight())
				{
					swap(dataList, j, j + 1);
				}

			}
		}
	}
}

   3) Test case

package edu.xmu.designPattern.DesignPattern_Strategy;

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

import org.junit.Before;
import org.junit.Test;

public class StrategyTest
{
	private List<Cat> dataList = new ArrayList<Cat>();

	@Before
	public void setUp()
	{
		dataList.add(new Cat(1, 1));
		dataList.add(new Cat(0, 2));
		dataList.add(new Cat(-1, 2));
		dataList.add(new Cat(-11, 2));
		dataList.add(new Cat(100, -1));
	}

	@Test
	public void test()
	{
		DataSorter.ascSort(dataList);

		for (Cat data : dataList)
		{
			System.out.println(data + ", ");
		}
		System.out.println("====================================");

		DataSorter.descSort(dataList);

		for (Cat data : dataList)
		{
			System.out.println(data + ", ");
		}
	}
}

   Comments:

        1) It seems that our DataSorter can be used for a random kind of Object.

        2) But what if we want use this to sort an array contains Dog?

            We have to change the code inside the sort function.

        3) What if when the height of cats are the same, we want to sort by weight?

            We have to change the code inside the sort function.

         Simply speaking, our sorter is tightly coupled with the class it want to sort.

3. A better approach for explaining Comparable interface

    1) Comparable interface

package edu.xmu.designPattern.DesignPattern_Strategy;

public interface Comparable
{
	public int compare(Comparable o);
}

    2) Cat class that implements this interface

package edu.xmu.designPattern.DesignPattern_Strategy;

public class Cat implements Comparable
{
	private int height;
	private int weight;

	public Cat(int height, int weight)
	{
		super();
		this.height = height;
		this.weight = weight;
	}

	public int getHeight()
	{
		return height;
	}

	public void setHeight(int height)
	{
		this.height = height;
	}

	public int getWeight()
	{
		return weight;
	}

	public void setWeight(int weight)
	{
		this.weight = weight;
	}

	@Override
	public String toString()
	{
		return "Cat [height=" + height + ", weight=" + weight + "]";
	}

	public int compare(Comparable o)
	{
		Cat c = (Cat) o;
		return this.getHeight() >= c.getHeight() ? (this.getHeight() == c
				.getHeight() ? (this.getWeight() >= c.getWeight() ? 1 : -1) : 1)
				: -1;
	}

}

   3) DataSort class that coupled with interface Comparable instead of concrete class

package edu.xmu.designPattern.DesignPattern_Strategy;

import java.util.List;

public class DataSorter
{
	public static void ascSort(List<Comparable> dataList)
	{
		// bubble sort
		for (int i = 0; i < dataList.size(); i++)
		{
			for (int j = 0; j < dataList.size() - i - 1; j++)
			{
				if (1 == dataList.get(j).compare(dataList.get(j + 1)))
				{
					swap(dataList, j, j + 1);
				}

			}
		}
	}

	private static void swap(List<Comparable> dataList, int i, int j)
	{
		Comparable temp = dataList.get(i);
		dataList.set(i, dataList.get(j));
		dataList.set(j, temp);
	}

	public static void descSort(List<Comparable> dataList)
	{
		// bubble sort
		for (int i = 0; i < dataList.size(); i++)
		{
			for (int j = 0; j < dataList.size() - i - 1; j++)
			{
				if (-1 == dataList.get(j).compare(dataList.get(j + 1)))
				{
					swap(dataList, j, j + 1);
				}
			}
		}
	}
}

  4) Test case

package edu.xmu.designPattern.DesignPattern_Strategy;

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

import org.junit.Before;
import org.junit.Test;

public class StrategyTest
{
	private List<Comparable> dataList = new ArrayList<Comparable>();

	@Before
	public void setUp()
	{
		dataList.add(new Cat(1, 1));
		dataList.add(new Cat(0, 2));
		dataList.add(new Cat(-1, 2));
		dataList.add(new Cat(-11, 2));
		dataList.add(new Cat(100, -1));
	}

	@Test
	public void test()
	{
		DataSorter.ascSort(dataList);
		for (Comparable data : dataList)
		{
			System.out.println(data + ", ");
		}
	}
}

   Class Diagram:

    Comments:

        1) By using this, we simply decoupling the compare function with the sort function.

        2) Think of the System.out.println(obj) is simply call the obj.toString() instead of using other approach.

            This decoupled the two kinds of class.

         3) This is quite the same with the interface in JDK called java.lang.Comparable

4. A even more better approach

    1) When we came up with the way we used above. It seems all right.

        But what if we want to change the compare strategy for a cat?

        We have to change the code inside the Cat class.

        What if we want a certain list of cat compare based on the height + weight, and another list of cat compare based on the weight + height?

        The way before cannot realize this.

    2) The solution above couples the class with the compare function.

         And the compare function is not extensiable.

    3) The class diagram is as below


    1. Cat.java

package edu.xmu.designPattern.DesignPattern_Strategy;

public class Cat
{
	private int height;
	private int weight;

	public Cat(int height, int weight)
	{
		super();
		this.height = height;
		this.weight = weight;
	}

	public int getHeight()
	{
		return height;
	}

	public void setHeight(int height)
	{
		this.height = height;
	}

	public int getWeight()
	{
		return weight;
	}

	public void setWeight(int weight)
	{
		this.weight = weight;
	}

	@Override
	public String toString()
	{
		return "Cat [height=" + height + ", weight=" + weight + "]";
	}
}

    2.Comparator interface

package edu.xmu.designPattern.DesignPattern_Strategy;

public interface Comparator
{
	public int compare(Object obj1, Object obj2);
}

    3. One kind of compare strategy for Cat

package edu.xmu.designPattern.DesignPattern_Strategy;

public class CatComparatorBasedOnWeight implements Comparator
{

	public int compare(Object obj1, Object obj2)
	{
		Cat cat1 = (Cat) obj1;
		Cat cat2 = (Cat) obj2;

		return cat1.getWeight() >= cat2.getWeight() ? (cat1.getWeight() == cat2
				.getWeight() ? (cat1.getHeight() >= cat2.getHeight() ? 1 : -1)
				: 1) : -1;
	}

}

    4. Another kind of compare strategy for Cat

package edu.xmu.designPattern.DesignPattern_Strategy;

public class CatComparatorBasedOnHeight implements Comparator
{

	public int compare(Object obj1, Object obj2)
	{
		Cat cat1 = (Cat) obj1;
		Cat cat2 = (Cat) obj2;

		return cat1.getHeight() >= cat2.getHeight() ? (cat1.getHeight() == cat2
				.getHeight() ? (cat1.getWeight() >= cat2.getWeight() ? 1 : -1)
				: 1) : -1;
	}

}

    5. The core sort function

package edu.xmu.designPattern.DesignPattern_Strategy;

import java.util.List;

public class DataSorter
{
	public static void ascSort(List<Object> dataList, Comparator comparator)
	{
		// bubble sort
		for (int i = 0; i < dataList.size(); i++)
		{
			for (int j = 0; j < dataList.size() - i - 1; j++)
			{
				if (1 == comparator.compare(dataList.get(j),
						dataList.get(j + 1)))
				{
					swap(dataList, j, j + 1);
				}

			}
		}
	}

	private static void swap(List<Object> dataList, int i, int j)
	{
		Object temp = dataList.get(i);
		dataList.set(i, dataList.get(j));
		dataList.set(j, temp);
	}

	public static void descSort(List<Object> dataList, Comparator comparator)
	{
		// bubble sort
		for (int i = 0; i < dataList.size(); i++)
		{
			for (int j = 0; j < dataList.size() - i - 1; j++)
			{
				if (-1 == comparator.compare(dataList.get(j),
						dataList.get(j + 1)))
				{
					swap(dataList, j, j + 1);
				}
			}
		}
	}
}

    6. The test case

package edu.xmu.designPattern.DesignPattern_Strategy;

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

import org.junit.Before;
import org.junit.Test;

public class StrategyTest
{
	private List<Object> dataList = new ArrayList<Object>();

	@Before
	public void setUp()
	{
		dataList.add(new Cat(1, 1));
		dataList.add(new Cat(0, 2));
		dataList.add(new Cat(-1, 2));
		dataList.add(new Cat(-11, 2));
		dataList.add(new Cat(100, -1));
	}

	@Test
	public void test()
	{
		DataSorter.ascSort(dataList, new CatComparatorBasedOnWeight());
		for (Object data : dataList)
		{
			System.out.println(data + ", ");
		}
	}
}

    Comments:

         1) By using this, we simply decoupling the compare function with the real object.

         2) And we decoupled the sort function with the real object.which can easily be seen in the class diagram above.

         3) We can even add an attribute in class Cat called comparator and then Cat implements Comparable which has a compareTo method and its realization is use this comparator to get result.

5. A far more better approach

    1. Class diagram is as below


     2. Cat.java

package edu.xmu.designPattern.DesignPattern_Strategy;

public class Cat implements Comparable
{
	private int height;
	private int weight;

	private Comparator comparator = new CatComparatorBasedOnHeight();

	public Cat(int height, int weight)
	{
		super();
		this.height = height;
		this.weight = weight;
	}

	public int getHeight()
	{
		return height;
	}

	public void setHeight(int height)
	{
		this.height = height;
	}

	public int getWeight()
	{
		return weight;
	}

	public void setWeight(int weight)
	{
		this.weight = weight;
	}

	public Comparator getComparator()
	{
		return comparator;
	}

	public void setComparator(Comparator comparator)
	{
		this.comparator = comparator;
	}

	@Override
	public String toString()
	{
		return "Cat [height=" + height + ", weight=" + weight + "]";
	}

	public int compare(Comparable o)
	{
		return comparator.compare(this, o);
	}
}

    3. Core sort function

package edu.xmu.designPattern.DesignPattern_Strategy;

import java.util.List;

public class DataSorter
{
	public static void ascSort(List<Comparable> dataList)
	{
		// bubble sort
		for (int i = 0; i < dataList.size(); i++)
		{
			for (int j = 0; j < dataList.size() - i - 1; j++)
			{
				if (1 == dataList.get(j).compare(dataList.get(j + 1)))
				{
					swap(dataList, j, j + 1);
				}

			}
		}
	}

	private static void swap(List<Comparable> dataList, int i, int j)
	{
		Comparable temp = dataList.get(i);
		dataList.set(i, dataList.get(j));
		dataList.set(j, temp);
	}

	public static void descSort(List<Comparable> dataList)
	{
		// bubble sort
		for (int i = 0; i < dataList.size(); i++)
		{
			for (int j = 0; j < dataList.size() - i - 1; j++)
			{
				if (-1 == dataList.get(j).compare(dataList.get(j + 1)))
				{
					swap(dataList, j, j + 1);
				}
			}
		}
	}
}

猜你喜欢

转载自davyjones2010.iteye.com/blog/1881696