如何编写通用比较器,可以对所有必要的字段进行排序? [英] How write universal comparator which can make sorting through all necessary fields?

查看:113
本文介绍了如何编写通用比较器,可以对所有必要的字段进行排序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在班级的所有字段上实现排序
我为班级中的每个字段编写了一个比较器。
但是我必须为每个字段写一个单独的比较器。
我认为它不是很正确。
如何为我的班级编写一个可以对所有字段进行排序的通用比较器?

I needed to implement sorting on all fields of my class I wrote a comparator for each field in my class. But I had to write a individual comparator for each field. I think that it is not very correctly. How write for my class a single universal comparator which can make sorting through all fields?

我的实体:

public class User {
    private long id;
    private String name;
    private int age;
 .....................

我的比较器:

public class UserComparatorById implements Comparator<User> {   
    public int compare(User user1, User user2) {        
       int result = (int)(user1.getId() - user2.getId());
       if (result != 0) return (int)(result/Math.abs(result));        
       result = user1.getName().compareTo (user2.getName());
       if (result != 0) return (int)(result/Math.abs(result));
       result = user1.getAge() - user2.getAge();
       return (result != 0) ? (int)(result/Math.abs(result)) : 0;
    }
}







public class UserComparatorByName implements Comparator<User> { 
    public int compare(User user1, User user2) {            
       int result = user1.getName().compareTo (user2.getName());
       if (result != 0) return (int)(result/Math.abs(result));
       result = (int)(user1.getId() - user2.getId());
       if (result != 0) return (int)(result/Math.abs(result));  
       result = user1.getAge() - user2.getAge();
       return (result != 0) ? (int)(result/Math.abs(result)) : 0;
    }
}







public class UserComparatorByAge implements Comparator<User> {  
    public int compare(User user1, User user2) {            
       int result = user1.getAge() - user2.getAge();
       if (result != 0) return (int)(result/Math.abs(result));
       result = (int)(user1.getId() - user2.getId());
       if (result != 0) return (int)(result/Math.abs(result));   
       result = user1.getName().compareTo (user2.getName());
       return (result != 0) ? (int)(result/Math.abs(result)) : 0;
    }
}

排序:

List<User> users = new ArrayList<User>();

    users.add(new User(5, "Frank", 28));
    users.add(new User(1, "Jorge", 19));
    users.add(new User(6, "Bill", 34));
    users.add(new User(3, "Michel", 17));
    users.add(new User(7, "Mark", 42));

    UserComparatorByName comparatorByName = new UserComparatorByName();
    Collections.sort(users, comparatorByName);

    UserComparatorByAge comparatorByAge = new UserComparatorByAge();
    Collections.sort(users, comparatorByAge);


推荐答案

每个字段的一个实现并不坏,但是你的代码中有很多重复。每个字段应该有一个比较器。如果您想基于几个字段进行比较,但顺序不同,请包装 atomic 比较器( Decorator 模式):

One implementation per field isn't that bad, however there is a lot of duplication in your code. You should have one comparator per exactly one field. If you want to compare based on several fields but in different order, wrap atomic comparators (Decorator pattern):

public abstract class AbstractComparator implements Comparator<User> {
    private final AbstractComparator next;

    public AbstractComparator(AbstractComparator next) {
        this.next = next;
    }

    public int compare(User user1, User user2) {
        int result = doCompare(user1, user2);
        if (result != 0) {
            return result;
        } else {
            return next != null? next.compare(user1, user2) : 0;
        }
    }

    public abstract int doCompare(User user1, User user2);
}







class ById extends AbstractComparator {
    public ById(AbstractComparator next) {
        super(next);
    }

    public int doCompare(User user1, User user2) {
        return (int) (user1.getId() - user2.getId());
    }
}







class ByName extends AbstractComparator {
    public ByName(AbstractComparator next) {
        super(next);
    }

    public int doCompare(User user1, User user2) {
        return user1.getName().compareTo(user2.getName());
    }
}







class ByAge extends AbstractComparator {
    public ByAge(AbstractComparator next) {
        super(next);
    }

    public int doCompare(User user1, User user2) {
        return user1.getAge() - user2.getAge();
    }
}

用法:

Comparator<User> comp1 = new ById(new ByName(new ByAge(null)));
Comparator<User> comp2 = new ByAge(new ByName(new ById(null)));

comp1 首先按<$ c $排序c> id 如果它相等,则回退到 name age as万不得已。 API非常清楚。

comp1 first sorts by id and if it is equal, falls back to name and to age as a last resort. The API is pretty clear.

为方便起见,您应将所有 By * 类作为<$的静态内部类c $ c>用户: User.ByName User.ByAge 等等或可能有一些工厂方法: User.byName(User.byAge(null))。借助一些静态导入,您可以获得愉快的效果:

For convenience you should place all By* classes as static inner classes of User: User.ByName, User.ByAge, etc. or maybe with some factory methods: User.byName(User.byAge(null)). With a help of some static imports you can echieve pleasant:

Collections.sort(users, byName(byAge(byId(null))));

或者看看 CompareToBuilder

这篇关于如何编写通用比较器,可以对所有必要的字段进行排序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆