排序算法包实现

在学习面向对象课程的过程中,为了理解面向对象设计的基本原则和设计思想,我设计了两种排序算法包以来说明在面向对象开发过程中要注意的一些设计原则。题目要求是这样的:

      设计一个负责排序的程序包,实现多种排序算法,至少包括插入排序、冒泡排序和快速排序算法。

      要求:

      1.可以对任何简单类型和任意对象进行排序

2.可以支持升序、降序、字典排序等多种顺序要求

3.可以随意增加排序算法和顺序要求,保证其他程序不修改

4.减少程序代码中逻辑上的冗余

      我的第一种实现方式:通过继承实现

首先定义一个父类Sorter,在这个父类中有一个抽象方法(延迟方法)

protected abstract void sort(boolean isAscend,Object[] array);//isAscend 表示是否按升序排列,array表示待排序的对象数组




     这个抽象方法必须由子类去实现,而每一个子类都可以用不同的排序算法来实现这个抽象方法。

父类初了这个抽象方法外还定义了所有的排序方法,但是这些方法都是final的,即不可继续覆写的,比如其中一个对int[]进行排序的方法:


final void sortIntArray(int[] array,boolean isAscend) {
    //第一步:转化
Integer[] integers = new Integer[array.length];
for(int i = 0;i<array.length;i++)
integers[i]=array[i];
//第二步:设置比较器
this.setCompator(new IntCompator());	
//第三步:使用自身的抽象方法进行排序
this.sort(isAscend, integers);
//第四步:将排序后的结果复制到原数组中
for(int j = 0;j<integers.length;j++)
array[j]=integers[j];
}


在这里我还要提一下我的两种实现方法的基本思想:首先我不区分Primitive类型的还是对象类型的,我都是对对象数组进行排序。而在对对象数组排序的时候需要使用自定义的比较器(这我这个实现中两种方法都用到了比较器MyCompator).所谓的比较器其实就是我自定义个一个接口用来比较两个对象之间的先后顺序的,其定义如下:   

public interface MyCompator {
int compare(Object o1,Object o2);//0:两者部分先后   < 0:o1在o2之后   > 0 :o1在o2之后

}


那我是怎么对基本数据类型进行排序的呢? 这很简单,总共分为四步(参见上面的代码)。这样我就不需要再去区分基本数据类型和对象类型的,当然在这个排序包中,我自己定义了很多比较器用来对基本数据类型进行排序,比如:

public class IntCompator implements MyCompator
{
	@Override
	public int compare(Object o1, Object o2) {
		Integer t1 = (Integer)o1;
		Integer t2 = (Integer)o2;
		return t1.compareTo(t2);
	}
}


总共9个这样的类。

      说完父类,下面说一说子类,其中有一个子类,如下:


public class BubbleSorter extends Sorter {
	public BubbleSorter( MyCompator a) {
		super(a);
	}
	public BubbleSorter() {
		super();
	}
	
	@Override
	public void sort(boolean isAscend,Object[] array) {
		if(isAscend)
		{
			for (int i = 0; i < array.length-1; i++) {
				for (int j = 0; j < array.length-i-1; j++) {
					if(compator.compare(array[j], array[j+1])>0)
						swap(array,j,j+1);
				}
			}
			
		}
		else
		{
			for (int i = 0; i < array.length-1; i++) {
				for (int j = 0; j < array.length-i-1; j++) {
					if(compator.compare(array[j], array[j+1])<0)
						swap(array,j,j+1);
				}
			}
		}
	}
	private void swap(Object[] array, int j, int i) {
		Object temp =array[j];
		array[j] = array[i];
		array[i] = temp;
		
	}
}



可以看到,子只是覆写了父类的抽象方法,而其他方法父类已经在语法上对其禁止覆写了(父类有很有final的方法)。当需要增加其他排序算法时,只需要再新增加一个类继承于Sorter父类就行了。这样就很好了符合了面向对象设计的一个很重要的原则:开闭原则。所谓开闭原则就是:软件系统中包含的各种组件,例如模块(Modules)、类(Classes)以及功能(Functions)等等,应该在不修改现有代码的基础上,引入新功能。开闭原则中“开”,是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的;开闭原则中“闭”,是指对于原有代码的修改是封闭的,即不应该修改原有的代码。 

另外还体现了依赖倒转原则,所谓依赖倒转原则就是:要依赖于抽象,不要依赖于实现。要针对接口编程,不要针对实现编程。

下面是一个测试程序:

public class Demo {
	public static void main(String[] args) {
//		Integer[] integers = new Integer[]{1,2,8785,6,1,9999};
//		QuickSorter s = new QuickSorter(integers,new IntegerCompator());
//		s.sort(false);
//		s.print();
		
		//Dog[] dogs = new Dog[]{new Dog(3),new Dog(88),new Dog(-1)};
		
		/*BubbleSorter b = new BubbleSorter(dogs, new DogCompator());
		b.sort(false);
		b.print();*/
		/*QuickSorter q = new QuickSorter(dogs,new DogCompator());
		q.sort(false);
		q.print();*/
		
		/*InsertSorter inserter = new InsertSorter(dogs, new DogCompator());
		inserter.sort(false);
		inserter.print();*/
		int[] a = new int[]{4,6,0,22};
		new BubbleSorter().sortIntArray(a, true);
		
		for (int i = 0; i < a.length; i++) {
			System.out.println(a[i]);
		}
	}
}
class Dog
{
	public Dog(int height)
	{
		this.height = height;
	}
	int height;
	@Override
	public String toString() {
		return "height="+height;
	}
}
class DogCompator implements MyCompator
{
	@Override 
	public int compare(Object o1, Object o2) {
		Dog d1 = (Dog)o1;
		Dog d2 = (Dog)o2;
		if(d1.height>d2.height)
			return 1;
		else if(d1.height==d2.height)
			return 0;
		else
			return -1;
	}
}




    下面是第一种方案的UML图





   

还有另外一种基于策略模式的设计方法。

      首先定义一个排序器接口:

public interface Sorter {
	void sort(Object[] array,boolean isAscend);
}



然后在选择排序算法的时候就可以对其进行实现,即不同的排序算法可以自成一个类并实现该接口,如:

public class BubbleSorter implements Sorter {
	@Override
	public void sort(Object[] array, boolean isAscend) {
		......//这里是具体算法的实现,当然也是需要用到比较器的。
	}
}


接着再定义一个ArraySorter,它拥有一个成员变量Sorter,这个成员变量负责排序功能的真正的实现。其简单定义如下:

public class ArraySorter {
	private Sorter sorter;
	public void setSorter(Sorter sorter) {
		this.sorter = sorter;
	}
	public ArraySorter()
	{
			
	}
	public ArraySorter(Sorter sorter) {
		this.sorter = sorter;
	}
	public void sort(Object[] array,boolean isAscend)
	{
		sorter.sort(array, isAscend);
	}
	public void sortIntArray(int[] array)
	{
	
	}
	.......//还有好多对其他类型数组的排序,这里就不写了。
}



这样在实际排序的时候,我们就可以随意的更换排序器,即使用不同的算法来进行排序,这里就用到了策略模式。策略模式通常包含三种角色:抽象策略角色: 1)策略类,通常由一个接口或者抽象类实现(在这个实现中就是Sorter接口);2)具体策略角色:包装了相关的算法和行为(就是BubbleSorter类和其他实现了该接口的类);3)环境角色:持有一个策略类的引用,最终给客户端调用(即ArraySorter).策略模式实际上是定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换(在这里就是可以随意替换排序器)。策略模式让算法独立于使用它的客户而独立变化。

      但是策略模式也会带来一些缺点就是因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。其实基本上每一个设计模式都会有这样一个缺点,不过这对于维护而言不算什么。

 

      好了,我总算是完成了我在CSDN上的第一篇文章了。如果有什么需要改进的地方,请各位大神及时指正。

     



    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值