Christian
Christian

Reputation: 3972

Passing class type in to a filter function

I am trying to return a filtered list of rooms by the room Class (SurgeryRoom or TechRoom). Is there a way to do it by passing the room Class in as an argument to getAvailableRooms() instead of having the two private methods?

import java.util.*;

public class RoomBooker {

    private List<IRoom> rooms = new ArrayList<>();

    public RoomBooker() {
        // Demo data
        rooms.add(new SurgeryRoom("Surgery 1"));
        rooms.add(new SurgeryRoom("Surgery 2"));
        rooms.add(new TechRoom("TechRoom 1"));
        rooms.add(new TechRoom("TechRoom 2"));
    }

    private List<IRoom> filterBySurgeryRoom() {
        List<IRoom> r = new ArrayList<>();
        for (IRoom room : rooms) {
            if (room instanceof SurgeryRoom) {
                r.add(room);
            }
        }
        return r;
    }

    private List<IRoom> filterByTechRoom() {
        List<IRoom> r = new ArrayList<>();
        for (IRoom room : rooms) {
            if (room instanceof TechRoom) {
                r.add(room);
            }
        }
        return r;
    }

    public List<IRoom> getAvailableRooms(String roomType, Date date) {  
        List<IRoom> available = new ArrayList<>();

        switch (roomType.toUpperCase()) {
            case "SURGERY":
                available = filterBySurgeryRoom();
                break;
            case "TECH":
                available = filterByTechRoom();
                break;
        }

        return available;
    }
}

Upvotes: 0

Views: 728

Answers (3)

Ousmane D.
Ousmane D.

Reputation: 56413

make the method accept a Predicate parameter i.e:

private List<IRoom> filterRoomByType(Predicate<IRoom> predicate) {
        List<IRoom> r = new ArrayList<>();
        for (IRoom room : rooms) {
            if (predicate.test(room)) {
                r.add(room);
            }
        }
        return r;
}

so now whenever you call the method filterRoomByType, you can pass in a function which defines the criteria for the if condition.

filterRoomByType(e -> e instanceof SurgeryRoom);

or

filterRoomByType(e -> e instanceof TechRoom);

Upvotes: 2

azro
azro

Reputation: 54148

You can use Java Streams to achieve this easily

public List<IRoom> getAvailableRooms(Class<? extends IRoom> roomType, Date date) {
    return rooms.stream().filter(roomType::isInstance).collect(Collectors.toList());
}

And call with :

List<IRoom> list = getAvailableRooms(SurgeryRoom.class, new Date(1234));
List<IRoom> list = getAvailableRooms(TechRoom.class, new Date(1234));

Later when you'll add the date filter you'd be able to use the same method just improve the filter part

Like getting all rooms for specific class AND those which date is after date in parameter :

public List<IRoom> getAvailableRooms(Class<? extends IRoom> roomType, Date date) {
    return rooms.stream()
            .filter(roomType::isInstance)         //== .filter(r->roomType.isInstance(r))
            .filter(r -> r.getDate().after(date))
            .collect(Collectors.toList());
}

Upvotes: 2

Sven Tschui
Sven Tschui

Reputation: 1425

Pass in the class as an argument and use the isInstance method documented here: https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#isInstance(java.lang.Object)

private <T extends IRoom> List<T> filterRoomByType(Class<T> roomType) {
    List<T> r = new ArrayList<>();
    for (IRoom room : rooms) {
        if (roomType.isInstance(room)) {
            r.add((T) room);
        }
    }
    return r;
}

Upvotes: 3

Related Questions