简体   繁体   English

如何弄清楚抽象列表中的对象是什么?

[英]How to figure out what object is in a abstract list?

I have an abstract class called sessions. 我有一个名为sessions的抽象类。 Lectures and tutorials extend sessions. 讲座和教程扩展了会话。 Then I have a class called enrollment which holds a list of sessions (Lectures & tutorials). 然后我有一个名为enrollment的类,它包含一个会话列表(讲座和教程)。 How can I loop through the session list in Enrolment and return a list of Lectures only from the session list? 如何在“注册”中循环访问会话列表并仅从会话列表返回讲座列表?

My next question is should I instead store 2 lists. 我的下一个问题是我应该存储2个列表。 One list of Lectures and one list of Tutorials, instead of 1 session list? 一个讲座列表和一个教程列表,而不是一个会话列表? This is because the sessions list is useless to me and I have to loop through it each time to get information about lectures and tutorials. 这是因为会话列表对我来说是无用的,我每次都必须遍历它以获取有关讲座和教程的信息。 Is there a way I am missing to get all the lectures objects? 有没有办法让我得到所有的讲座对象? I am new to java. 我是java的新手。

public class Enrolment {

    private List<Session> sessions;

    public Enrolment() {
        this.sessions = new ArrayList<>();
    }

    public addSession(Session session) {
        this.sessions.add(session);
    }
}

public class Session {

    private int time;

    public Session(int time) {
        this.time = time;
    }
}

public class Lecture extends Session {

    private String lecturer;

    public Lecture(int time, String lecturer) {
        super(time);
        this.lecturer = lecturer;
    }
}

public class Tutorial extends Session {

    private String tutor;
    private int tutorScore;

    public Tutorial(int time, String tutor, int tutorScore) {
        super(time);
        this.tutor = tutor;
        this.tutorScore = tutorScore;
    }

}

public class test {
    public static void main(String[] args) {
        Enrolment newEnrolment = new Enrolment();

        Lecture morningLec = new Lecture(900, "Dr. Mike");
        newEnrolment.addSession(morningLec);

        Tutorial afternoonTut = new Tutorial(1400, "John Smith", 3);
        newEnrolment.addSession(afternoonTut);

        Lecture middayLec = new Lecture(1200, "Mr. Micheals");
        newEnrolment.addSession(middayLec);

        Tutorial NightTut = new Tutorial(1900, "Harry Pauls", 4);
        newEnrolment.addSession(NightTut);
    }
}

Stream the sessions list and use instanceof to filter the Lectures type objects sessions列表并使用instanceof过滤Lectures类型对象

List<Lecture> l = sessions.stream()
                           .filter(Lecture.class::isInstance) 
                           .map(Lecture.class::cast)                               
                           .collect(Collectors.toList());

By using for loop use two different lists for each type 通过使用for循环,为每种类型使用两个不同的列表

List<Lecture> l = new ArrayList<>();
List<Tutorial> t = new ArrayList<>();
for (Session s : sessions) {
    if (s instanceof Lecture) {
        l.add((Lecture) s);
    }
      else if(s instanceof Tutorial) {
        t.add((Tutorial) s);
    }
}

Maybe you should store in two lists, just like: 也许你应该存储在两个列表中,就像:

public class Enrolment {

    private List<Lecture> lectures;
    private List<Tutorial> tutorials;

    public Enrolment() {
        this.lectures = new ArrayList<>();
        this.tutorials = new ArrayList<>();
    }

    public void addSession(Session session) {
        if (session instanceof Lecture) {
            lectures.add((Lecture) session);
        } else if (session instanceof  Tutorial) {
            tutorials.add((Tutorial) session);
        }
    }

    public List<Lecture> getLectures() {
        return lectures;
    }

    public List<Tutorial> getTutorials() {
        return tutorials;
    }

    public List<Session> getAllSessions() {
        ArrayList<Session> sessions = new ArrayList<>(lectures);
        sessions.addAll(tutorials);
        return sessions;
    }
}

Is that what you need? 这就是你需要的吗?

My next question is should I instead store 2 lists. 我的下一个问题是我应该存储2个列表。 One list of Lectures and one list of Tutorials, instead of 1 session list? 一个讲座列表和一个教程列表,而不是一个会话列表? This is because the sessions list is useless to me and I have to loop through it each time to get information about lectures and tutorials. 这是因为会话列表对我来说是无用的,我每次都必须遍历它以获取有关讲座和教程的信息。 Is there a way I am missing to get all the lectures objects? 有没有办法让我得到所有的讲座对象?

You answered yourself to your problem. 你回答了自己的问题。
When you start to write too complex/boiler plate code to make things that should be simple such as iterating on a list of objects that you have just added, it is a sign that you should step back and redesign the thing. 当你开始编写过于复杂的/样板代码来制作应该简单的东西时,例如迭代你刚刚添加的对象列表,这表明你应该退后一步并重新设计。

By introducing Enrolment.addSession(Session session) , you introduced an undesirable abstraction : 通过引入Enrolment.addSession(Session session) ,您引入了一个不受欢迎的抽象:

public class Enrolment {

    private List<Session> sessions;

    public Enrolment() {
        this.sessions = new ArrayList<>();
    }

    public addSession(Session session) {
        this.sessions.add(session);
    }
}

You don't want to handle uniformally Lecture and Tutorial from the Enrolment point of view, so just don't merge them in the same List only because these rely on the same interface ( Session ). 您不希望从Enrolment角度处理统一的LectureTutorial ,因此只是因为它们依赖于相同的接口( Session )而不能将它们合并到同一个List
Abstraction has to be used when it is required and not systematically because that is possible. 必要时必须使用抽象,而不是系统地使用抽象,因为这是可能的。
Don't you add all objects in a List of Object because all is Object ? 你不是在对象列表中添加所有对象,因为所有对象都是对象吗? No. 没有。

Instead of, create this distinction both from the API method and from its implementation : 而不是从API方法及其实现中创建这种区别:

public class Enrolment {

    private List<Conference> conferences = new ArrayList<>();
    private List<Tutorial> tutorials = new ArrayList<>();


    public addConference(Conference conference) {
        this.conferences.add(conference);
    }

    public addTutorial(Tutorial tutorial) {
        this.tutorials.add(tutorial);
    }
}

And use it : 并使用它:

Lecture morningLec = new Lecture(900, "Dr. Mike");
newEnrolment.addLecture(morningLec);

Tutorial afternoonTut = new Tutorial(1400, "John Smith", 3);
newEnrolment.addTutorial(afternoonTut);

Note that you could have a scenario where you need to manipulate uniformally Tutorial and Lecture for some processings but that for others you want to distinguish them. 请注意,您可能需要一个场景,您需要对一些处理进行统一的Tutorial和Lecture操作,但对于其他您希望区分它们的场景。
In this case, you have some common ways : 在这种情况下,您有一些常见的方法:

  • instanceOf : easy to use but also easy to make a code brittle. instanceOf :易于使用但也易于使代码变脆。 For example, later you could add a new subclass in the Session hierarchy and without be aware of it, instances of this subclass could be included or excluded in some processing without that the compiler warns you. 例如,稍后您可以在Session层次结构中添加一个新的子类,而不必了解它,可以在某些处理中包含或排除此子类的实例,而不会让编译器发出警告。

  • provide a abstract method that returns a boolean or an enum to convey the nature of the object (ex: isLecture() ). 提供一个抽象方法,返回一个布尔值或一个枚举来传达对象的性质(例如: isLecture() )。 More robust than instanceOf since the compiler constraints you to override the method but it may also lead to error prone code if multiple subclasses are added and that the filters are not only on Lecture but Lecture and another type. instanceOf更强大,因为编译器限制你覆盖方法,但是如果添加了多个子类并且过滤器不仅在Lecture而且是Lecture和另一种类型,它也可能导致容易出错的代码。 So I would favor this way while the filtering condition stays simple. 所以我倾向于这种方式,而过滤条件保持简单。

  • define three lists : one for lectures, another for conferences and another that contains all of these that should be handled uniformally. 定义三个列表:一个用于讲座,另一个用于会议,另一个包含应该统一处理的所有这些列表。 More complex way but more robust way too. 更复杂的方式,但也更健壮的方式。 I would favor it only for cases with complex/changing filtering conditions. 我赞成它仅适用于具有复杂/变化的过滤条件的情况。

        List<Lecture> l = newEnrolment.getSessions()
            .stream()
            .filter(s-> s.getClass().equals(Lecture.class))
            .map(session -> (Lecture) session)
            .collect(Collectors.toList());

!!! Don't use typeof 不要使用typeof

Quoting from your question, 引用你的问题,

This is because the sessions list is useless to me. 这是因为会话列表对我来说没用。

So, this is probably not the right place to have the list(?). 所以,这可能不是获得列表的正确位置(?)。

My preference would be to have 我的偏好是


public interface Enrolment {
    public abstract addSession(Session session);
    public abstract getSessions();
}

And List<LectureEnrolment> and List<TutorialEnrolment> must be in their respective classes.(I have renamed Lecture to LectureEnrolment and Tutorial to TutorialEnrolment ) List<LectureEnrolment>List<TutorialEnrolment>必须在各自的类中。(我已将Lecture重命名为LectureEnrolmentTutorial TutorialEnrolment

main() must have something like, main()必须有类似的东西,

Enrolment lectureEnrolment= new LectureEnrolment()

Enrolment tutorialEnrolement = new TutorialEnrolment()

call the respective addSession() or getSession() depending on requirement. 根据需要调用相应的addSession()getSession()

change private List<Session> sessions; 更改private List<Session> sessions; to public List<Session> sessions; public List<Session> sessions; in class Enrolment class Enrolment

public static void main(String[] args) {
    ....
    var lecturesAndTutorials = newEnrolment.sessions.where(x => x.getType() == typeof(Lecture) || x.getType() == typeof(Tutorial));
    ....
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM