oop - How can I link an object to another object in Java? - Stack Overflow

时间: 2025-01-06 admin 业界

I am building a movie theatre application in Java and need some help with linking objects. I have created three classes: Person, Movie, and Extra.

Currently, I have a scenario where a Person (like John or Sam) can add a Movie (like "Fight Club") to their list of movies. I want to ensure that each person can choose different extras for the same movie. However, when I add an extra (e.g., "Popcorn") to a movie, it gets added for all people watching that movie, rather than just the individual person.

Here's an example:

John wants to watch "Fight Club" and add the extra "Popcorn." Sam wants to watch the same movie but prefers the extra "Drink." The problem is that when I add "Popcorn" to the movie, it ends up being added to the movie for both John and Sam, instead of just for John.

Here’s my code:

Person:

public class Person {
    private String name;
    private int attendeesCount;
    private List<Movie> movies;

    public Person(String name, int attendeesCount) {
        this.name = name;
        this.attendeesCount = attendeesCount;
        this.movies = new ArrayList<>();
    }

    public void addMovie(Movie movie) {
        movies.add(movie);
    }
}

Movie:

public class Movie {
    private String title, description;
    private int price, duration;
    private List<Extra> extras = new ArrayList<>();

    private Movie(String title, int price, String description, int duration) {
        this.title = title;
        this.price = price;
        this.description = description;
        this.duration = duration;
    }

    public void addExtra(Extra extra) {
        this.extras.add(extra);
    }
}

Extra:

public class Extra {
    private String name;
    private int price;

    public Extra(String name, int price) {
        this.name = name;
        this.price= price;
    }
}

Main:

public class TestTheatre {
    public static void main(String[] args) {
        Movie fightClub = new Movie("Fight Club", 1000, null, 90);
        Movie theMatrix = new Movie("The Matrix", 2000, null, 80);

        Extra popcorn = new Extra("Popcorn", 500);
        Extra drink = new Extra("Drink", 400);

        fightClub.addExtra(popcorn); // Here is where I am adding the extra to the movie

        Person john = new Person("John", 2);
        Person sam = new Person("Sam", 3);

        john.addMovie(fightClub);
        john.addMovie(theMatrix);

        sam.addMovie(fightClub);
    }
}

I understand that the issue occurs because I’m adding extras to the movie globally, which applies the extras to all persons who watch that movie however, I just can't work out how I can solve this. Any help would be greatly appreciated.

I am building a movie theatre application in Java and need some help with linking objects. I have created three classes: Person, Movie, and Extra.

Currently, I have a scenario where a Person (like John or Sam) can add a Movie (like "Fight Club") to their list of movies. I want to ensure that each person can choose different extras for the same movie. However, when I add an extra (e.g., "Popcorn") to a movie, it gets added for all people watching that movie, rather than just the individual person.

Here's an example:

John wants to watch "Fight Club" and add the extra "Popcorn." Sam wants to watch the same movie but prefers the extra "Drink." The problem is that when I add "Popcorn" to the movie, it ends up being added to the movie for both John and Sam, instead of just for John.

Here’s my code:

Person:

public class Person {
    private String name;
    private int attendeesCount;
    private List<Movie> movies;

    public Person(String name, int attendeesCount) {
        this.name = name;
        this.attendeesCount = attendeesCount;
        this.movies = new ArrayList<>();
    }

    public void addMovie(Movie movie) {
        movies.add(movie);
    }
}

Movie:

public class Movie {
    private String title, description;
    private int price, duration;
    private List<Extra> extras = new ArrayList<>();

    private Movie(String title, int price, String description, int duration) {
        this.title = title;
        this.price = price;
        this.description = description;
        this.duration = duration;
    }

    public void addExtra(Extra extra) {
        this.extras.add(extra);
    }
}

Extra:

public class Extra {
    private String name;
    private int price;

    public Extra(String name, int price) {
        this.name = name;
        this.price= price;
    }
}

Main:

public class TestTheatre {
    public static void main(String[] args) {
        Movie fightClub = new Movie("Fight Club", 1000, null, 90);
        Movie theMatrix = new Movie("The Matrix", 2000, null, 80);

        Extra popcorn = new Extra("Popcorn", 500);
        Extra drink = new Extra("Drink", 400);

        fightClub.addExtra(popcorn); // Here is where I am adding the extra to the movie

        Person john = new Person("John", 2);
        Person sam = new Person("Sam", 3);

        john.addMovie(fightClub);
        john.addMovie(theMatrix);

        sam.addMovie(fightClub);
    }
}

I understand that the issue occurs because I’m adding extras to the movie globally, which applies the extras to all persons who watch that movie however, I just can't work out how I can solve this. Any help would be greatly appreciated.

Share Improve this question edited yesterday Progman 19.4k7 gold badges51 silver badges78 bronze badges asked yesterday John BowlerJohn Bowler 182 bronze badges 2
  • 3 I don't want to be a pedant, but "linking" is a weird term. Usually we think in terms of "has-a" and "is-a". These terms better match OOP and what you will actually do in the code. For example a Person has-a MovieTicket and a MovieTicket might have (has-a) upgrade or extra. Thinking like that will help you design code. – markspace Commented yesterday
  • A bit of a tangent, but why does a Person have an attendeesCount? I haven't looked through much of the code, but it doesn't make sense to put it there. – ndc85430 Commented yesterday
Add a comment  | 

3 Answers 3

Reset to default 7

As you already have identified, you shouldn't add the extras to the movies. The extras are not part of the movies so delete the private List<Extra> extras field from the Movie class. Same goes with the list of movies in the Person class. The movies are not part of a person.

Instead, depending on what you want to do, create a new Reservation or Booking class, which references a Person and a Movie. This class can have your List<Extra> field for the extras the person is having when watching the movie.

Tip: Thoughtful naming can be critical in discerning a proper design for your software.

Let's make Extras more specific: Food (although the stuff at theaters barely qualifies).

If the menu of Food items and their price are known at compile-time, then make the class an enum.

package work.basil.example.collections.theater;

enum Food
{
    SODA ( 1 ),
    BEER ( 4 ),
    POPCORN ( 2 ),
    JUJUBE ( 1 );

    final int price;

    Food ( final int thePrice )
    {
        this.price = thePrice;
    }
}

And “Person” should really be Customer. But you are not actually tracking the customer. You seem to be tracking only the purchases made by any customer, pairing each admission to a movie with optional food items. This could be realistic, I suppose, especially for online orders made ahead of time. (Stating the business requirements clearly and specifically is another crucial element of software design. Your requirements statement is vague, lacking detail.)

So your apparent requirements means we have a Purchase object needing a reference to a Movie object, as well as a reference to a Collection of zero or more Food objects.

So we need a Movie class.

If the primary purpose of a class is to transparently communicate shallowly-immutable data, make it a record. This class merely represents each movie being shown. This is not the place to track purchases.

Regarding the duration of the movie, we have a class for that: Duration. We can use that as the type of our member field rather than your choice of int.

public record Movie( String title , int price , String description , Duration duration ) { }

Our Theater object comes with a list of the currently-playing movies.

The theater sells admission tickets and food items, not the movie. So we have maintain a collection of Purchase objects here.

public class Theater
{
    final List < Movie > movies;
    final Collection < Purchase > purchases = new ArrayList <> ( );

    public Theater ( final List < Movie > theMovies )
    {
        this.movies = theMovies;
    }
}

Back to our Purchase class. We can track each purchase with a UUID. And we need the movie along with the food items being purchased.

package work.basil.example.collections.theater;

import java.util.Collection;
import java.util.UUID;

public record Purchase
        (
                UUID id ,
                Movie movie , 
                Collection < Food > foodItems
        )
{ }

And an app class to pull it all together.

public class App
{
    public static void main ( String[] args )
    {
        App app = new App ( );
        app.demo ( );
    }

    private void demo ( )
    {
        Theater theater =
                new Theater (
                        List.of (
                                new Movie ( "Fight Club" , 5 , "Brad Pitt" , Duration.ofMinutes ( 92 ) ) ,
                                new Movie ( "A River Runs Through It" , 4 , "Brad Pitt & Robert Redford" , Duration.ofMinutes ( 101 ) ) ,
                                new Movie ( "Thelma & Louise" , 7 , "Brad Pitt, Susan Sarandon, and Geena Davis" , Duration.ofMinutes ( 87 ) )
                        )
                );

        theater.purchases.add (
                new Purchase (
                        UUID.randomUUID ( ) ,
                        theater.movies.get ( 0 ) ,
                        List.of ( Food.POPCORN )
                )
        );

        theater.purchases.add (
                new Purchase (
                        UUID.randomUUID ( ) ,
                        theater.movies.get ( 0 ) ,
                        List.of ( Food.SODA )
                )
        );
    }
}

And now we see the solution to your Question, How can I link an object to another object in Java?. When making a purchase, we create a collection (here, a List) of food items to be passed to the constructor of Purchase. That list of food choices is associated with a movie by both being fields on the Purchase class. In turn, each new Purchase object gets added to a collection of purchases kept somewhere (here, on the Theater class).

In a real app, we would have a GUI where the user would select the movie being purchased, and select the zero, one, or more food items to go with that movie ticket.

        Movie movie = gui.getMovie() ;  // Which in turn would have done something like: `theater.movies.get ( 0 )` from a scroll box.
        List < Food > foods = gui.getFoods() ;  // Which in turn would have done something like: `List.of ( Food.POPCORN )`. 
        theater.purchases.add (
                new Purchase (
                        UUID.randomUUID ( ) ,
                        movie ,
                        foods
                )
        );
        gui.updatePurchaseComplete() ;

To start off on the right foot, we must ask ourselves questions:

1°) what do we have?

a) Theatre
b) Room
c) Movie
d) ServiceExtra
e) Product
f) Customer

2°) “who” has “what”?

a) Theatre has Room
b) Room has Movie, has ServiceExtra
c) ServiceExtra has Product, has Customer
D) Customer has money, we have to take it away!!!

let's create our classes:

class Theatre {
   Room rooms[];
}

class Room {
   Movie movie;
   ServiceExtra;
   int seats[]
}

class ServiceExtra {
   Product products[];
   Map<Customer, List<Product>> extra;
}

class Customer {
   int seatNumber;
   String name;
}

class Movie {}

class Product {}

This example is not intended to be the final form of your code (missing fields, methods, etc), nor the best strategy to use, I just hope it serves as a starting point.