В предыдущей статье мы узнали о том, как JAVA реализует концепцию наследования для создания иерархий классов https://medium.com/@konlanmikpekoah.km/understanding-inheritance-using-java-bbe184bc824b.

В этом примере мы увидим, как мы можем использовать концепцию, называемую композицией, для создания сложных объектов из более простых. Итак, вы, возможно, помните, что модель наследования — это тип отношений.

Итак, здесь, на этой диаграмме классов, объект книги является публикацией, поскольку он наследуется от базового класса публикации, а также получает все атрибуты и методы из базового класса. Таким образом, мы также можем сказать, что журнал — это периодическое издание, и мы можем видеть, что журнал — это публикация, потому что, опять же, он имеет тот же общий базовый класс.

Состав работает немного по-другому. При использовании композиции мы строим объекты из других объектов, и эта модель больше похожа на взаимосвязь.

Итак, на приведенной выше диаграмме объект книги имеет объект автора, который содержит информацию об авторе. Вместо того, чтобы определять всю информацию, связанную с автором, непосредственно в иерархии классов книги. Этот тип модели позволяет нам извлекать отдельные идеи и помещать их в свои собственные классы. Теперь наследование и композиция не исключают друг друга, вы можете комбинировать их в зависимости от потребностей вашего приложения. Итак, давайте применим эту концепцию к реальному коду, чтобы увидеть, как это работает.

Book.java

import java.util.ArrayList;
import java.util.List;

public class Book {
    private String title;
    private double price;
    private  String authorFname;
    private  String authorLname;
    List<String> chapters = new ArrayList();

    public Book(String title, double price, String authorFname,     String authorLname) {
        this.title = title;
        this.price = price;
        this.authorFname = authorFname;
        this.authorLname = authorLname;
    }

    public void addChapter(String chapterName){
        chapters.add(chapterName);
    }

}

И я определил класс книги, есть название и цена, а также некоторая информация об авторе, имя и фамилия, и есть атрибут для хранения списка информации о главах. Также есть метод добавления глав в книгу, и он берет название главы и добавляет его в список массивов. Это конкретное определение класса прекрасно и хорошо, но оно довольно монолитно.

Есть фрагменты информации, такие как автор и, возможно, информация о главах, которые имеет смысл рассматривать как отдельные сущности. Нетрудно представить себе сценарий, в котором мы могли бы захотеть работать только с группой авторов или получить информацию о конкретных главах книги. Таким образом, мы можем использовать композицию, чтобы отделить эти отдельные фрагменты информации от общего объекта книги. Итак, давайте начнем с извлечения информации об авторе в отдельный класс.

Автор.java

public class Author {
    private String firstName;
    private String lastName;

    public Author(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

Итак, мне нужно изменить класс книги, чтобы использовать объект автора в качестве аргумента в конструкторе.

Book.java

import java.util.ArrayList;
import java.util.List;

public class Book {
    private String title;
    private double price;
    private Author author;
    List<String> chapters = new ArrayList();

    public Book(String title, double price, Author author) {
        this.title = title;
        this.price = price;
        this.author = author;
    }

    public void addChapter(String chapterName){
        chapters.add(chapterName);
    }

}

Итак, теперь мы создали отношения, в которых с книгой связан автор, вместо того, чтобы хранить детали реализации данных об авторе внутри класса книги.

Итак, давайте продолжим и создадим отдельный класс для глав.

мы даже добавили pageCount для каждой главы в классе глав.

public class Chapter {
    private String name;
    private  int pageCount;

    public Chapter(String name, int pageCount) {
        this.name = name;
        this.pageCount = pageCount;
    }
}

теперь мы создали отношение, в котором книга имеет набор объектов глав. Мы даже можем добавить новый метод, и мы назовем его получить количество страниц книги, с помощью которого книга может вычислить свое собственное количество страниц.

import java.util.ArrayList;
import java.util.List;

public class Book {
    private String title;
    private double price;
    private Author author;
    List<Chapter> chapters = new ArrayList();

    public Book(String title, double price, Author author) {
        this.title = title;
        this.price = price;
        this.author = author;
    }

    public void addChapter(Chapter chapter){
        chapters.add(chapter);
    }

    public int totalPageNumber(){
        int result = 0;
        for( Chapter chapter: chapters){
            result += chapter.getPageCount();
        }
        return result;
    }

}

Итак, теперь у нас есть хорошее разделение обязанностей. Так, например, печать полного имени автора выполняется в классе author. Так что мы можем распечатать автора книги, а название оставим в покое. И вычисление размера книги выполняется с использованием данных, которые находятся в классе глав. У нас есть извлеченные объекты главы и автора, и мы обновили класс книги, чтобы вместо этого использовать эти данные.

в заключение

Итак, мы взяли монолитное определение класса и сделали его более расширяемым и гибким, составив его из более простых объектов класса, каждый из которых отвечает за свои функции и данные.