首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用迭代器模式遍历不同的准则

使用迭代器模式遍历不同的准则
EN

Stack Overflow用户
提问于 2016-12-18 03:10:45
回答 2查看 185关注 0票数 0

以下是问题所在:

假设我有大量的Person对象集合,并且需要以不同的方式遍历列表。例如,重复一份1980年出生或居住在纽约市的人的名单。使用ITERATOR模式写下代码,对出生在特定年份的人进行迭代。请注意,代码必须易于修改或扩展,以便可以使用不同的标准。

首先,我为Person类使用了构建器模式。

代码语言:javascript
复制
public class Person {
//mandatory
private final String SSN;          //social security number
private final MyDate DOB;          //date of birth
private String name;               //name

//optional
private String phone;              //phone number
private USAddress address;         //home address
private USAddress workAddress;     //work address
private Set<USAddress> FVA;        //frequently visited addresses
private Set<Person> familyMembers; //family members

private Person(PersonBuilder builder){
    ...
}

第二,集装箱类的人。

代码语言:javascript
复制
public class PersonList extends ArrayList<Person> {

public PersonList() {
    super();
}

//our list only stores unique elements
@Override
public boolean add(Person person) {
    return !this.contains(person) && super.add(person);
}

//person iterator
public PersonIterator personIterator() {
    return new PersonIterator(this);
}
}

最后,我实现迭代器模式的方法。

代码语言:javascript
复制
public class PersonIterator implements Iterator<Person> {
private int index;
private Mode mode;           //iteration mode
private List<Person> origin; //ref to the input list
private List<Person> temp;   //used to store sublist 

//iteration mode
private enum Mode {
    NORMAL,
    YEAR,
    CITY
}

//constructor, the default mode is normal
public PersonIterator(PersonList list){
    mode = Mode.NORMAL;
    index = 0;
    origin = list;
    temp = new ArrayList<>();
}

//set to normal mode
public void normalMode(){
    index = 0;
    mode = Mode.NORMAL;
}

//set to year mode
public void yearMode(int year){
    index = 0;
    mode = Mode.YEAR;
    temp.clear();
    for(Person p: origin){
        if(p.getDOB().getYear() == year){
            temp.add(p);
        }
    }
}

//set to city mode
public void cityMode(String city){
    index = 0;
    mode = Mode.CITY;
    temp.clear();
    for(Person p: origin){
        if(p.getAddress().getCity().equals(city)){
            temp.add(p);
        }
    }
}

//
@Override
public boolean hasNext() {
    if(mode == Mode.NORMAL){
        return index < origin.size();
    }
    else{
        return index < temp.size();
    }
}

@Override
public Person next() {
    if(mode == Mode.NORMAL){
        if(!this.hasNext()){
            throw new NoSuchElementException();
        }
        Person p = origin.get(index);
        index++;
        return p;
    }
    else{
        if(!this.hasNext()){
            throw new NoSuchElementException();
        }
        Person p = temp.get(index);
        index++;
        return p;
    }
}
}

对于不同的准则,它有几种迭代模式。正常模式只是遍历列表,仅此而已。例如,另一种模式,即年份模式,将在该年出生的所有perons添加到临时子列表中,然后正常遍历此临时子列表。

要添加更多模式,请执行以下操作:

  1. 在枚举中创建模式
  2. 创建"xMode“方法,并定义如何填充临时子列表

我测试了恳求。

代码语言:javascript
复制
public static void main(String[] args) {

    Person john = new Person.PersonBuilder("110", 1980, 8, 2, "john")
            .phone("120")
            .address("1000", "5th", "ave", "11F", "New York", "NY", 11345)
            .workAddress()
            .addFVA(null)
            .addFamilyMember(null)
            .build();

    Person adam = new Person.PersonBuilder("120", 1980, 11, 22, "adam")
            .phone("130")
            .address("31", "main", "st", "", "Stony Brook", "NY", 11411)
            .workAddress()
            .addFVA(null)
            .addFamilyMember(null)
            .build();

    Person lucy = new Person.PersonBuilder("130", 1978, 1, 3, "lucy")
            .phone("140")
            .address("1200", "6th", "ave", "2A", "New York", "NY", 11346)
            .workAddress()
            .addFVA(null)
            .addFamilyMember(null)
            .build();

    PersonList list = new PersonList();
    list.add(john);
    list.add(adam);
    list.add(lucy);
    PersonIterator i = list.personIterator();
    //normal iterator
    while(i.hasNext()){
        System.out.println(i.next().getName() + " is in the list");
    }

    //year mode, print out persons who were born in 1980
    i.yearMode(1980);
    while(i.hasNext()){
        System.out.println(i.next().getName() + " was born in 1980");
    }

    //city mode, print out persons who live in New York City
    i.cityMode("New York");
    while (i.hasNext()){
        System.out.println(i.next().getName() + " lives in NYC");
    }

这是结果。

代码语言:javascript
复制
john is in the list
adam is in the list
lucy is in the list
john was born in 1980
adam was born in 1980
john lives in NYC
lucy lives in NYC

所以我的问题是:

  1. 我的方法能解决这个问题吗?如果没有,请指出一个更好的方法。
  2. 代码容易阅读,易于修改吗?如果没有,如何改进?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-12-18 03:37:24

我认为你的解决方案有点过分,而且效率不高。您需要的大部分东西已经由Java提供了。因此,我有以下建议:

1-与其扩展ArrayList<Person>并重写add方法以获得唯一性,不如考虑使用java.util.Set。如果您需要保持插入顺序,请使用LinkedHashSet<Person>,否则只需使用HashSet<Person>。在大多数情况下,对集合进行子类化不是一个好主意。

2-您试图实现的只是简单的过滤,这可以简单地完成&使用Java 8的流API非常优雅。与创建自定义迭代器不同,只需使用stream的filter操作即可。类似于:

代码语言:javascript
复制
people.stream().filter(person -> person.getBirthYear() == 1980).forEach(person -> System.out.println(person.getName() + " was born in 1980"));

或者,如果您想在一个新的集合中收集它们,比方说,收集到一个新的、无序的集合:

代码语言:javascript
复制
people.stream().filter(person -> person.getBirthYear() == 1980).collect(Collectors.toSet());

您可以连锁多个过滤器:

代码语言:javascript
复制
people.stream().filter(person -> person.getBirthYear() == 1980).filter(person -> "New York".equals(person.getAddress().getCity())).collect(Collectors.toSet());
票数 0
EN

Stack Overflow用户

发布于 2016-12-18 04:00:56

你可以用反射

代码语言:javascript
复制
public boolean matchesCriteria(Person p, String value, Object tester) {
    Field f = p.getClass().getDeclaredField(value);
    f.setAccessible(true);
    Object o = f.get(p);
    if(o.equals(tester)) {
        return true;
    }
    return false;
}

然后,您可以通过使用for循环来调用它,以切换列表中的所有Person类并检查值。

代码语言:javascript
复制
DOB dob = new DOB(//However you create a DOB in the year 1980);
for(Person p : pList) {
    if(matchesCriteria(p, DOB, dob) {
        System.out.println(p.getName(), "Was born in the year 1980");
    }
}

会把1980年出生的人都送回去。你可以改变周围的一些东西,使它适合这个方法,或者根据你的喜好改变方法。

这将获得Person类中的特定字段,确保(如果它是私有的)使其在类之外可访问,并获得其值。然后,代码将检查这两个对象是否相同,并返回布尔值。

一个例子是,如果您有一个标记为“age”的字段:(只是为了显示代码如何与我所知道的变量一起工作)。因为我不知道你是如何创建一个MyYear的)

代码语言:javascript
复制
private int age;

for(Person p : pList) {
    if(matchesCriteria(p, "age", 9) {
        System.out.println(p.getName(), " is 9 year(s) old.");
    }
}

这使得matchesCriteria( Person,String,Object);对于Person类中的任何字段都是通用的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41205119

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档