接下来我们聊一聊对象数组排序,有排序那肯定有两两比较的过程;对于对象而言,其中有很多属性方法,我们可以通过某个属性进行比较,进而实现对对象数组的排序,对于下面程序:
Student stu1 = new Student("张三",12,153.4);
Student stu2 = new Student("李四",14,163.4);
Student stu3 = new Student("王五",13,123.4);
Student stu4 = new Student("赵六",4,6.4);
Student[] stus = {stu1,stu2,stu3,stu4};
复制代码
Student类中的有参构造器中的参数分别为:姓名、年龄、身高;其中stus就是对象数组,现在我需要通过年龄对stus数组进行排序,那么我们就可以通过冒泡排序实现,具体如下:
for (int i = 0; i < stus.length-1; i++) {
for (int j = 0; j < stus.length - i - 1; j++) {
if(stus[j].age > stus[j+1].age){
Student temp = stus[j];
stus[j] = stus[j+1];
stus[j+1] = temp;
}
}
}
复制代码
通过上述代码我们就可以将对象数组通过年龄进行排序;在上述代码中比较年龄就是一个比较策略,我们可以改变策略,比如比较身高,那么我们就需要让对象调用属性height。
承接上述,我们就以对象数组排序来慢慢理解策略设计模式;
首先我们创建User类,存放属性和方法,做为实例化对象的原始类;
public class User {
//创建属性
private String name;
private int age;
private int height;
//创建构造方法(若自己建立有参构造,须把无参构造加上)
public User() {
}
public User(String name, int age, int height) {
this.name = name;
this.age = age;
this.height = height;
}
//创建get/set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
//重写toString()方法
@Override
public String toString() {
return "User{" +
"name='" + name + ''' +
", age=" + age +
", height=" + height +
'}';
}
}
复制代码
创建Client类,用来实例化对象,封装对象数组,然后实现通过年龄进行进行对象数组排序;
public class Client {
//主函数中创建对象,封装对象数组
public static void main(String[] args) {
//创建User对象
User user1 = new User("张三",12,153);
User user2 = new User("李四",14,163);
User user3 = new User("王五",13,133);
User user4 = new User("赵六",11,143);
//封装对象数组
User[] users = {user1,user2,user3,user4};
//通过年龄对数组进行正向排序
for (int i=0;i < users.length - 1;i++){
for (int j=0;j < users.length - i - 1;j++){
if(users[j].getAge() > users[j+1].getAge()){
User temp = users[j];
users[j] = users[j+1];
users[j+1] = temp;
}
}
}
//输出查看对象数组是否排序成功
System.out.println(Arrays.toString(users));
}
}
复制代码
结果如下:
存在问题:我们可以看到已经排序成功;但是上述代码存在的问题是【将实现的细节暴露给了客户,并且比较也应该更面向对象一点】
解决方法:对于比较来说,我们可以改进比较方法,对比较进行封装,使得改变比较策略,而不复写代码;在此我们可以联想到equals()方法,因此我们可以抽离出一个让两个User对象进行比较的接口Comparable,然后让User实现该接口,从而完善Client中的比较细节;
创建Comparable接口,定义compare()方法;
public interface Comparable {
//封装比较方法,传入User对象,实现与调用对象的比较
Integer compare(Object object);
}
复制代码
更新User类,让其继承Comparable接口,实现compare()方法;
public class User implements Comparable{
/**
* 同之前的一样,就是增加了下面的这个方法
*/
//返回两个对象的比较的结果
@Override
public Integer compare(Object object) {
//如果传进来的是一个User类型的对象,那么再继续往下比,否则直接返回null
if(object instanceof User){
//首先将传进来的Object类型转换为User类型
User user = (User) object;
//返回比较的结果
return this.getAge() - user.getAge();
}
return null;
}
}
复制代码
Clien类中的排序方法中的比较就变得更加简洁,users[j].compare(users[j+1])
//通过年龄对数组进行正向排序
for (int i=0;i < users.length - 1;i++){
for (int j=0;j < users.length - i - 1;j++){
if(users[j].compare(users[j+1]) > 0){
User temp = users[j];
users[j] = users[j+1];
users[j+1] = temp;
}
}
}
复制代码
上述这种写法的好处:让所有对象拥有了可比较的能力(这也是接口的好处),并且将具比的东西转给了对象;
问题:如果按其他属性去排序,也就是改变排序策略,那么还是得去修改User中的compaer方法,这样还是不符合开闭原则,且细节还是暴露在外边,扩展性也差;
截至目前的两个问题:
根据单一原则,我们构建UserSorter类,实现排序方法;
public class UserSorter {
//创建实现对象排序功能的方法sort
public void sort(User[] users){
//通过年龄对数组进行正向排序
for (int i=0;i < users.length - 1;i++){
for (int j=0;j < users.length - i - 1;j++){
if(users[j].compare(users[j+1]) > 0){
User temp = users[j];
users[j] = users[j+1];
users[j+1] = temp;
}
}
}
}
}
复制代码
因此我们可将Client中实现比较的代码转换为 userSorter.sort(users)
public class Client {
//主函数中创建对象,封装对象数组
public static void main(String[] args) {
//创建User对象
User user1 = new User("张三",12,153);
User user2 = new User("李四",14,163);
User user3 = new User("王五",13,133);
User user4 = new User("赵六",11,143);
//封装对象数组
User[] users = {user1,user2,user3,user4};
//创建UserSorter对象
UserSorter userSorter = new UserSorter();
//调用UserSorter中的sort方法实现排序
userSorter.sort(users);
//输出查看对象数组是否排序成功
System.out.println(Arrays.toString(users));
}
}
复制代码
截至目前,我们就将实现细节屏蔽在Usersorter类中,并且让排序方法面向对象实现;
既然在改变比较策略时不想修改User类中的代码,那么我们就不让User类去实现Comparable接口;然后比较器UserSorer中的sort方法就得改!如果我们将sort中的比较策略写死,比如就写比较年龄,那我们改变比较策略的时候,比如想比较身高,那么就一定会对代码进行修改,但我们要对修改关闭,因此我们可以将User中的比较方法抽出去,让其不具备比较的能力;那么我们就可以想到建立一个类,让其拥有比较两个对象的能力,最终我们只需要将users[j],users[j+1],做为参数传入建立夫人那个类中的哪个方法中,最终让它返回比较的结果就行;
这样就对User本身无侵入性,就实现了不改动User代码;
我们现在定义这个类叫做Comparator,其中比较两个对象的方法为compare(User user,User user1);
public class Comparator {
public Integer compare(User user,User user1){
return user.getAge() - user1.getAge();
}
}
复制代码
那么UserSorter中的`sort方法就需要加参数,改进比较;
public class UserSorter {
//创建实现对象排序功能的方法sort
public void sort(User[] users,Comparator comparator){
//通过年龄对数组进行正向排序
for (int i=0;i < users.length - 1;i++){
for (int j=0;j < users.length - i - 1;j++){
if(comparator.compare(users[j],users[j+1]) > 0){
User temp = users[j];
users[j] = users[j+1];
users[j+1] = temp;
}
}
}
}
}
复制代码
Client中在调用sort方法时就直接将比较器类Comparatornew进去就可;
//调用UserSorter中的sort方法实现排序
userSorter.sort(users,new Comparator());
复制代码
截至目前,我们这样写还是违背了开闭原则,【在这里我们定义方法时,参数要面向抽象、面向接口,这样扩展性强,如果面向具体实现类,那只能实现写死的那个类,扩展性就很差】;所以我们将sort(User[] users,Comparator comparator)中的第二个参数试着变成接口:
将Comparator改为接口;
public interface Comparator {
Integer compare(User user,User user1);
}
复制代码
创建CompareAgeStrategy类实现Comparator接口,作用为比较年龄策略;
public class CompareAgeStrategy implements Comparator{
public Integer compare(User user,User user1){
return user.getAge() - user1.getAge();
}
}
复制代码
这样写的话,我们在UserSorter中的sort方法里传入的就是接口,那么我们在Client类中调用sort方法时传入的参数就可以new 具体的比较策略,比如:
//实现了年龄策略比较
userSorter.sort(users,new CompareAgeStrategy());
复制代码
那么我们如果想比较身高的话,那就可以扩展一个比较身高策略类,传参数时直接new 比较身高策略类即可,这样就满足了不对源代码进行修改,只在源代码上进行扩展,这就满足了开闭原则,整个过程也诠释了策略设计模式;
创建CompareHeightStrategy类实现Comparator接口,作用为比较身高策略;
public class CompareHeightStrategy implements Comparator{
@Override
public Integer compare(User user, User user1) {
return user.getHeight() - user1.getHeight();
}
}
复制代码
修改Client中调用sort方法时穿的参数;
//实现了身高策略比较
userSorter.sort(users,new CompareHeightStrategy());
复制代码
最终结果:
至此,Client就只需要享受策略就ok;
页面更新:2024-03-07
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号