Inheritance, Interfaces, and Polymorphism

Abstract Classes and Interfaces

ReadingPreview

You are viewing a free preview lesson.

Lesson Overview

আগের lesson-এ ContentItem class-এ একটি default implementation রেখেছিলাম:

public int calculateEstimatedMinutes() {
    return 0;
}

এই implementation compile করে, কিন্তু domain perspective-এ দুর্বল।

একটি content item-এর estimated duration যদি সবসময় content type অনুযায়ী calculate করতে হয়, তাহলে generic parent-এর 0 return করা meaningful নয়।

আরও বড় সমস্যা হলো child class methodটি override করতে ভুলে যেতে পারে।

public class InteractiveLesson
        extends ContentItem {

}

এখন:

interactiveLesson
        .calculateEstimatedMinutes();

return করবে:

0

যদিও zero-minute lesson business perspective-এ invalid হতে পারে।

এমন situation-এ parent class বলতে পারে:

সব concrete child class-কে এই behavior implement করতেই হবে।

এর জন্য Java-তে abstract method এবং abstract class রয়েছে।

অন্যদিকে কিছু behavior shared state-এর অংশ নয়; এটি একটি capability বা contract।

Examples:

Publishable
Downloadable
Gradable
Completable

একটি class multiple capabilities support করতে পারে।

এর জন্য Java interface ব্যবহার করে।

এই lesson-এ আমরা শিখব:

  • Abstract class কী
  • Abstract method
  • Concrete behavior এবং shared state
  • Abstract constructor
  • Interface কী
  • implements
  • Multiple interfaces
  • Interface references
  • default এবং static methods
  • Abstract class এবং interface-এর পার্থক্য
  • Shared identity বনাম shared capability
  • কখন কোন abstraction ব্যবহার করা উচিত
  • Unnecessary inheritance এবং interface explosion avoid করা

Learning Objectives

এই lesson শেষ করার পর আপনি পারবেন:

  • Abstract class declare করতে
  • Abstract method তৈরি করতে
  • Concrete subclass-কে required behavior implement করতে বাধ্য করতে
  • Abstract class-এর constructor এবং shared state ব্যবহার করতে
  • Interface define এবং implement করতে
  • Interface type reference ব্যবহার করতে
  • একটি class-এ multiple interfaces implement করতে
  • Abstract class এবং interface-এর মধ্যে appropriate choice করতে
  • Capability-based interface design করতে
  • Overly broad এবং unnecessary interfaces identify করতে

The Problem with Meaningless Default Behavior

Parent:

public class ContentItem {

    public int calculateEstimatedMinutes() {
        return 0;
    }
}

Child override করতে পারে:

@Override
public int calculateEstimatedMinutes() {
    return durationInMinutes;
}

কিন্তু override বাধ্যতামূলক নয়।

public class AudioLesson
        extends ContentItem {

}

এখন inherited 0 silently ব্যবহার হবে।

Meaningless default implementation-এর পরিবর্তে আমরা methodটি abstract করতে পারি।


What Is an Abstract Method?

Abstract method শুধু contract declare করে।

এটির method body থাকে না।

public abstract int calculateEstimatedMinutes();

Notice:

  • abstract keyword আছে
  • Method body নেই
  • শেষে semicolon আছে

Wrong:

public abstract int calculateEstimatedMinutes() {
    return 0;
}

Abstract method-এর implementation থাকে না।


What Is an Abstract Class?

যে class abstract keyword দিয়ে declare করা হয়, সেটি abstract class।

public abstract class ContentItem {

}

Abstract class:

  • Shared state রাখতে পারে
  • Constructor রাখতে পারে
  • Concrete methods রাখতে পারে
  • Abstract methods রাখতে পারে
  • Directly instantiate করা যায় না
  • Child classes-এর common foundation হতে পারে

Declaring an Abstract Parent

public abstract class ContentItem {

    private final long id;
    private final String title;

    private boolean published;

    protected ContentItem(
            long id,
            String title
    ) {
        if (id <= 0) {
            throw new IllegalArgumentException(
                    "Content ID must be positive."
            );
        }

        if (
                title == null
                || title.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Content title is required."
            );
        }

        this.id = id;
        this.title = title.strip();
        this.published = false;
    }

    public abstract int calculateEstimatedMinutes();

    public abstract String getContentType();

    public boolean publish() {
        if (published) {
            return false;
        }

        published = true;

        return true;
    }

    public final long getId() {
        return id;
    }

    public final String getTitle() {
        return title;
    }

    public final boolean isPublished() {
        return published;
    }
}

এখানে:

calculateEstimatedMinutes()
getContentType()

abstract।

কিন্তু:

publish()
getId()
getTitle()
isPublished()

concrete methods।


Abstract Class Cannot Be Instantiated

Invalid:

ContentItem content =
        new ContentItem(
                1L,
                "General Content"
        );

Compile হবে না।

কারণ ContentItem incomplete abstraction।

এটি জানে না:

Content type কী?
Duration কীভাবে calculate হবে?

Concrete child object তৈরি করতে হবে।

ContentItem content =
        new VideoLesson(
                1L,
                "Abstract Classes",
                "https://cdn.liveklass.io/video/1",
                18
        );

Why Prevent Direct Instantiation?

যদি generic ContentItem domain-এ meaningful না হয়, direct creation prevent করা উচিত।

Valid content types:

VideoLesson
ArticleLesson
QuizLesson

Abstract parent নিশ্চিত করে:

  • Generic incomplete object তৈরি হবে না
  • Required specialized behavior implement হবে
  • Common state centralize থাকবে
  • Parent type polymorphically ব্যবহার করা যাবে

Abstract Class Can Have a Constructor

Abstract class instantiate করা যায় না, কিন্তু constructor থাকতে পারে।

protected ContentItem(
        long id,
        String title
) {
    this.id = id;
    this.title = title;
}

Child constructor parent constructor call করবে।

public VideoLesson(
        long id,
        String title,
        String videoUrl,
        int durationInMinutes
) {
    super(
            id,
            title
    );

    this.videoUrl =
            videoUrl;

    this.durationInMinutes =
            durationInMinutes;
}

Abstract constructor shared parent state initialize করে।


Why Is the Constructor protected?

protected ContentItem(...)

ContentItem direct instantiate করা যায় না।

Constructor মূলত subclasses-এর জন্য।

protected intent প্রকাশ করে:

This constructor supports subclass construction.

A public constructorও technically possible, কিন্তু abstract class-এর ক্ষেত্রে caller direct instantiate করতে পারে না।

protected অনেক সময় clearer।


Concrete Child Must Implement Abstract Methods

Parent:

public abstract int calculateEstimatedMinutes();

Concrete child:

public class VideoLesson
        extends ContentItem {

    private final int durationInMinutes;

    @Override
    public int calculateEstimatedMinutes() {
        return durationInMinutes;
    }

    @Override
    public String getContentType() {
        return "VIDEO";
    }
}

Concrete child required abstract methods implement না করলে compile error হবে।


An Abstract Child May Defer Implementation

public abstract class MediaLesson
        extends ContentItem {

    protected MediaLesson(
            long id,
            String title
    ) {
        super(
                id,
                title
        );
    }
}

MediaLesson নিজেও abstract হলে parent abstract methods implement না করেও থাকতে পারে।

Later concrete child implementation দেবে।

public class VideoLesson
        extends MediaLesson {

    @Override
    public int calculateEstimatedMinutes() {
        return durationInMinutes;
    }

    @Override
    public String getContentType() {
        return "VIDEO";
    }
}

তবে hierarchy unnecessary deep করা উচিত নয়।


Abstract and Concrete Methods Together

Abstract class-এর শক্তি হলো shared implementation এবং required specialization একসঙ্গে রাখা।

Shared:

public boolean publish() {
    if (published) {
        return false;
    }

    published = true;

    return true;
}

Specialized:

public abstract int calculateEstimatedMinutes();

এতে parent বলতে পারে:

Publication lifecycle সবার জন্য same
Duration calculation type-specific

Template Behavior

Parent একটি complete algorithm define করতে পারে, কিন্তু একটি specific step child-এর কাছে delegate করতে পারে।

public final boolean publish() {
    if (published) {
        return false;
    }

    if (!isReadyForPublication()) {
        return false;
    }

    published = true;

    return true;
}

protected abstract boolean isReadyForPublication();

Child:

@Override
protected boolean isReadyForPublication() {
    return videoUrl.startsWith(
            "https://"
    );
}

Parent publication flow control করছে।

Child শুধু readiness rule provide করছে।

এটিকে template-style behavior বলা যায়।


Why Make the Template Method final?

public final boolean publish()

Child পুরো publication algorithm override করতে পারবে না।

এটি parent invariant protect করে।

Child শুধু allowed extension point implement করে:

isReadyForPublication()

এতে parent control এবং child customization balanced থাকে।


Complete Abstract ContentItem

public abstract class ContentItem {

    private final long id;
    private final String title;

    private boolean published;

    protected ContentItem(
            long id,
            String title
    ) {
        if (id <= 0) {
            throw new IllegalArgumentException(
                    "Content ID must be positive."
            );
        }

        if (
                title == null
                || title.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Content title is required."
            );
        }

        this.id = id;
        this.title = title.strip();
        this.published = false;
    }

    public abstract int calculateEstimatedMinutes();

    public abstract String getContentType();

    protected abstract boolean isReadyForPublication();

    public final boolean publish() {
        if (published) {
            return false;
        }

        if (!isReadyForPublication()) {
            return false;
        }

        published = true;

        return true;
    }

    public final long getId() {
        return id;
    }

    public final String getTitle() {
        return title;
    }

    public final boolean isPublished() {
        return published;
    }

    @Override
    public String toString() {
        return "ContentItem{"
                + "id="
                + id
                + ", title='"
                + title
                + '\''
                + ", type="
                + getContentType()
                + ", estimatedMinutes="
                + calculateEstimatedMinutes()
                + ", published="
                + published
                + '}';
    }
}

What Is an Interface?

Interface একটি behavioral contract define করে।

public interface Downloadable {

    String getDownloadUrl();
}

Interface বলে:

যে class এই interface implement করবে, তাকে download URL provide করতে হবে।

Interface সাধারণত shared object state own করে না।

এটি capability express করে।


Implementing an Interface

public class VideoLesson
        extends ContentItem
        implements Downloadable {

    private final String videoUrl;

    @Override
    public String getDownloadUrl() {
        return videoUrl;
    }
}

implements keyword interface contract accept করে।


Interface Methods Are Public Contracts

Interface method:

String getDownloadUrl();

Conceptually এটি:

public abstract String getDownloadUrl();

Implementation অবশ্যই public হতে হবে।

Wrong:

@Override
protected String getDownloadUrl() {
    return videoUrl;
}

Compile হবে না।

Correct:

@Override
public String getDownloadUrl() {
    return videoUrl;
}

Interface as a Capability

Consider:

public interface Downloadable {

    String getDownloadUrl();
}

Only relevant classes implement করবে।

VideoLesson
        implements Downloadable
ArticleLesson
        implements Downloadable

কিন্তু live stream content download support না করলে implement করবে না।

LiveVideoLesson

এভাবে unsupported method parent class-এ force করতে হয় না।


Multiple Interfaces

Java class শুধু একটি class extend করতে পারে।

কিন্তু multiple interfaces implement করতে পারে।

public class QuizLesson
        extends ContentItem
        implements Gradable,
                   Completable {

}

Syntax:

implements FirstInterface,
           SecondInterface

এতে class multiple behavioral contracts support করতে পারে।


A Gradable Interface

public interface Gradable {

    int calculateScore(
            int correctAnswers
    );

    boolean hasPassed(
            int correctAnswers
    );
}

Implementation:

public class QuizLesson
        extends ContentItem
        implements Gradable {

    private final int questionCount;
    private final int passingScore;

    @Override
    public int calculateScore(
            int correctAnswers
    ) {
        if (
                correctAnswers < 0
                || correctAnswers > questionCount
        ) {
            throw new IllegalArgumentException(
                    "Correct answer count is invalid."
            );
        }

        return correctAnswers
                * 100
                / questionCount;
    }

    @Override
    public boolean hasPassed(
            int correctAnswers
    ) {
        return calculateScore(
                correctAnswers
        ) >= passingScore;
    }
}

Interface Reference

Interface type reference implementing object hold করতে পারে।

Gradable assessment =
        new QuizLesson(
                1L,
                "Java Quiz",
                10,
                70
        );

Caller interface contract use করতে পারে।

int score =
        assessment.calculateScore(
                8
        );

boolean passed =
        assessment.hasPassed(
                8
        );

Caller quiz-এর title, publication state বা internal fields জানে না।

সে শুধু grading capability-এর ওপর depend করছে।


Interface-Based Polymorphism

একাধিক unrelated classes same interface implement করতে পারে।

public class QuizLesson
        implements Gradable {

}
public class Assignment
        implements Gradable {

}

Common parent class প্রয়োজন নেই।

Method:

public static void printResult(
        Gradable gradable,
        int correctAnswers
) {
    System.out.println(
            gradable.calculateScore(
                    correctAnswers
            )
    );
}

এটি different implementations accept করতে পারে।


Abstract Class vs Interface: Core Difference

Abstract class সাধারণত shared identity, state এবং implementation-এর foundation।

Interface সাধারণত shared behavior বা capability contract।

Example:

VideoLesson is a ContentItem
VideoLesson is Downloadable
QuizLesson is Gradable

Here:

ContentItem → Common type hierarchy
Downloadable → Capability
Gradable → Capability

Abstract Class Can Store Instance State

public abstract class ContentItem {

    private final long id;
    private final String title;

    private boolean published;
}

Each object-এর own state থাকে।

Interface সাধারণত instance fields রাখে না।


Interface Fields Are Constants

Interface-এ field declare করলে এটি implicitly:

public static final

Example:

public interface Downloadable {

    int MAX_DOWNLOAD_ATTEMPTS = 3;
}

Conceptually:

public static final int MAX_DOWNLOAD_ATTEMPTS =
        3;

Per-object state নয়।

Interface-এ mutable instance state রাখা যায় না।


Avoid Using Interfaces as Constant Containers

Weak:

public interface AppConstants {

    String PLATFORM_NAME =
            "LiveKlass";

    int MAX_TITLE_LENGTH =
            150;
}

এটি behavioral contract নয়।

Focused constants appropriate class-এর কাছে রাখা better।

Course.MAX_TITLE_LENGTH

অথবা dedicated configuration class।


Interface Can Have Default Methods

Modern Java interface concrete default method রাখতে পারে।

public interface Downloadable {

    String getDownloadUrl();

    default boolean hasDownloadAvailable() {
        String url =
                getDownloadUrl();

        return url != null
                && !url.isBlank();
    }
}

Implementing classes methodটি inherit করবে।


Why Use a Default Method?

Default method useful হতে পারে যখন:

  • Contract-এর ওপর based common behavior আছে
  • Existing implementations break না করে interface evolve করতে হয়
  • Behavior simple এবং natural
  • Shared instance fields প্রয়োজন নেই

Example:

default boolean hasDownloadAvailable()

শুধু interface method getDownloadUrl() ব্যবহার করে।


Default Method Can Be Overridden

@Override
public boolean hasDownloadAvailable() {
    return isPublished()
            && Downloadable
                    .super
                    .hasDownloadAvailable();
}

InterfaceName.super.method() দিয়ে default implementation call করা যায়।

এটি advanced syntax হলেও conceptually parent method-এর super.method()-এর মতো।


Interface Static Methods

Interface static methodও রাখতে পারে।

public interface Downloadable {

    static boolean isSecureUrl(
            String url
    ) {
        return url != null
                && url.startsWith(
                        "https://"
                );
    }
}

Call:

Downloadable.isSecureUrl(
        videoUrl
);

Static interface method implementing object-এর instance method নয়।


Private Interface Methods

Modern Java interface private helper method রাখতে পারে।

private static boolean isPresent(
        String value
) {
    return value != null
            && !value.isBlank();
}

এগুলো default বা static methods-এর duplication reduce করতে পারে।

Beginner code-এ simple interface prefer করুন।


Multiple Default Method Conflict

Suppose:

public interface Publishable {

    default String getStatus() {
        return "PUBLISHABLE";
    }
}
public interface Downloadable {

    default String getStatus() {
        return "DOWNLOADABLE";
    }
}

Class implements both:

public class VideoLesson
        implements Publishable,
                   Downloadable {

}

Compiler বুঝবে না কোন default method use করবে।

Classকে override করতে হবে।

@Override
public String getStatus() {
    return "VIDEO";
}

Java ambiguity silently resolve করে না।


Interface Inheritance

একটি interface অন্য interface extend করতে পারে।

public interface ScoredAssessment
        extends Gradable,
                Completable {

}

Interface multiple interfaces extend করতে পারে।

Class inheritance-এর single-parent restriction এখানে apply করে না।


Interface Does Not Mean No Implementation

Old oversimplification:

Interfaces contain only abstract methods.

Modern Java-তে interface রাখতে পারে:

  • Abstract methods
  • default methods
  • static methods
  • Private helper methods
  • Constants

তবুও interface-এর central purpose behavioral contract।


Abstract Class Can Implement an Interface

public abstract class ContentItem
        implements Publishable {

}

Abstract class interface method immediately implement না করেও abstract থাকতে পারে।

Later concrete child implementation দিতে পারে।

অথবা abstract parent common implementation দিতে পারে।

@Override
public final boolean publish() {
    // Shared implementation
}

A Publishable Interface

public interface Publishable {

    boolean publish();

    boolean isPublished();
}

Abstract parent:

public abstract class ContentItem
        implements Publishable {

    private boolean published;

    @Override
    public final boolean publish() {
        if (published) {
            return false;
        }

        if (!isReadyForPublication()) {
            return false;
        }

        published = true;

        return true;
    }

    @Override
    public final boolean isPublished() {
        return published;
    }

    protected abstract boolean isReadyForPublication();
}

এখানে:

  • Interface external capability declare করেছে
  • Abstract class shared implementation দিয়েছে
  • Child readiness behavior customize করছে

When to Use an Abstract Class

Abstract class consider করুন যখন:

1. Types Share a Meaningful Base Identity

VideoLesson is a ContentItem
ArticleLesson is a ContentItem

2. Shared Instance State Exists

id
title
published

3. Shared Construction Rules Exist

ID validation
Title validation
Initial publication state

4. Shared Concrete Behavior Exists

publish()
getTitle()
isPublished()

5. Controlled Extension Points Are Needed

protected abstract boolean isReadyForPublication();

When to Use an Interface

Interface consider করুন যখন:

1. A Capability Must Be Expressed

Downloadable
Gradable
Completable
Searchable

2. Unrelated Classes Can Support the Behavior

QuizLesson and Assignment are Gradable

3. Multiple Contracts Are Needed

implements Gradable,
           Completable,
           Publishable

4. Caller Should Depend on Behavior, Not Concrete Type

void grade(
        Gradable assessment
)

5. External Implementation Must Be Replaceable

NotificationSender
PaymentGateway
ContentStorage

Dependency design Lesson 6-এ বিস্তারিত শেখানো হবে।


Abstract Class vs Interface Table

Abstract ClassInterface
extends দিয়ে use হয়implements দিয়ে use হয়
একটি class শুধু একটি class extend করতে পারেMultiple interfaces implement করা যায়
Instance fields রাখতে পারেInstance fields রাখতে পারে না
Constructor থাকতে পারেConstructor থাকে না
Abstract এবং concrete methods রাখতে পারেAbstract, default, static methods রাখতে পারে
Shared state এবং base identity-এর জন্য usefulCapability এবং contract-এর জন্য useful
Protected members থাকতে পারেMethods generally public contract
Stronger structural relationshipFlexible behavioral relationship

Use Both When Appropriate

A class একই সঙ্গে:

  • একটি abstract parent extend করতে পারে
  • Multiple interfaces implement করতে পারে
public class VideoLesson
        extends ContentItem
        implements Downloadable,
                   Completable {

}

Meaning:

VideoLesson is a ContentItem
VideoLesson is Downloadable
VideoLesson is Completable

Capability Interface Naming

Interfacesকে meaningful capability হিসেবে name করা যায়।

Common patterns:

Downloadable
Gradable
Publishable
Completable
NotificationSender
ContentRenderer
PaymentGateway

Avoid vague names:

Helper
Manager
Processor
Common
GenericService

Interface name callerকে contract-এর purpose জানানো উচিত।


Avoid Interface Explosion

Weak design:

HasId
HasTitle
CanPublish
CanCalculateDuration
CanShowTitle
CanReturnType

প্রতিটি one-method behavior-এর জন্য interface তৈরি করা codebase fragmented করতে পারে।

Tiny interface useful হতে পারে, কিন্তু শুধু তখনই যখন:

  • Real substitutable implementations আছে
  • Caller independently capabilityটি use করে
  • Boundary meaningful
  • Interface future dependency reduce করে

Do Not Create an Interface for Every Class

Unnecessary:

public interface CourseServiceInterface {

}
public class CourseService
        implements CourseServiceInterface {

}

যদি:

  • শুধু একটি implementation
  • No replacement need
  • No external boundary
  • No testing advantage
  • Contract meaningless

তাহলে interface extra abstraction হতে পারে।


Interface Before Implementation Is Not Always Better

“Program to interfaces” মানে every concrete class-এর আগে interface বানানো নয়।

Better meaning:

যেখানে callers interchangeable behavior থেকে benefit পায়, সেখানে concrete implementation-এর পরিবর্তে stable contract-এর ওপর depend করুন।

Abstraction real need থেকে আসা উচিত।


Avoid Abstract Classes Used Only as Utility Containers

Weak:

public abstract class StringUtils {

    public static String normalize(
            String value
    ) {
        return value.strip();
    }
}

Class abstract করে instantiation prevent করা technically possible।

কিন্তু utility class হলে clearer:

public final class StringUtils {

    private StringUtils() {
    }
}

Abstract class inheritance design-এর জন্য, utility container হিসেবে নয়।


Avoid Empty Abstract Parents

public abstract class BaseEntity {

}

If it provides:

  • No meaningful contract
  • No shared behavior
  • No shared invariant
  • No useful polymorphic role

তাহলে hierarchy unnecessary হতে পারে।

Common base class শুধু naming consistency-এর জন্য তৈরি করা উচিত নয়।


Marker Interfaces

Empty interface:

public interface PremiumContent {

}

এটি marker interface।

কোনো method নেই; শুধু type marker হিসেবে কাজ করে।

Java ecosystem-এ historical examples আছে:

Serializable
Cloneable

কিন্তু modern application design-এ marker interface often avoid করা যায়।

Alternatives:

  • Annotation
  • Explicit property
  • Capability method
  • Separate policy

Empty interface real polymorphic contract না দিলে value সীমিত।


A Complete Combined Example

Publishable.java

public interface Publishable {

    boolean publish();

    boolean isPublished();
}

Downloadable.java

public interface Downloadable {

    String getDownloadUrl();

    default boolean hasDownloadAvailable() {
        String url =
                getDownloadUrl();

        return url != null
                && !url.isBlank();
    }
}

Gradable.java

public interface Gradable {

    int calculateScore(
            int correctAnswers
    );

    boolean hasPassed(
            int correctAnswers
    );
}

ContentItem.java

public abstract class ContentItem
        implements Publishable {

    private final long id;
    private final String title;

    private boolean published;

    protected ContentItem(
            long id,
            String title
    ) {
        if (id <= 0) {
            throw new IllegalArgumentException(
                    "Content ID must be positive."
            );
        }

        if (
                title == null
                || title.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Content title is required."
            );
        }

        this.id = id;
        this.title = title.strip();
        this.published = false;
    }

    public abstract int calculateEstimatedMinutes();

    public abstract String getContentType();

    protected abstract boolean isReadyForPublication();

    @Override
    public final boolean publish() {
        if (published) {
            return false;
        }

        if (!isReadyForPublication()) {
            return false;
        }

        published = true;

        return true;
    }

    @Override
    public final boolean isPublished() {
        return published;
    }

    public final long getId() {
        return id;
    }

    public final String getTitle() {
        return title;
    }
}

VideoLesson.java

public final class VideoLesson
        extends ContentItem
        implements Downloadable {

    private final String videoUrl;
    private final int durationInMinutes;

    public VideoLesson(
            long id,
            String title,
            String videoUrl,
            int durationInMinutes
    ) {
        super(
                id,
                title
        );

        if (
                videoUrl == null
                || videoUrl.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Video URL is required."
            );
        }

        if (durationInMinutes <= 0) {
            throw new IllegalArgumentException(
                    "Video duration must be positive."
            );
        }

        this.videoUrl =
                videoUrl.strip();

        this.durationInMinutes =
                durationInMinutes;
    }

    @Override
    public int calculateEstimatedMinutes() {
        return durationInMinutes;
    }

    @Override
    public String getContentType() {
        return "VIDEO";
    }

    @Override
    protected boolean isReadyForPublication() {
        return Downloadable.isSecureUrl(
                videoUrl
        );
    }

    @Override
    public String getDownloadUrl() {
        return videoUrl;
    }
}

The previous interface needs the static method:

public interface Downloadable {

    String getDownloadUrl();

    default boolean hasDownloadAvailable() {
        String url =
                getDownloadUrl();

        return url != null
                && !url.isBlank();
    }

    static boolean isSecureUrl(
            String url
    ) {
        return url != null
                && url.startsWith(
                        "https://"
                );
    }
}

ArticleLesson.java

public final class ArticleLesson
        extends ContentItem
        implements Downloadable {

    private static final int WORDS_PER_MINUTE =
            200;

    private final String content;
    private final String downloadUrl;

    public ArticleLesson(
            long id,
            String title,
            String content,
            String downloadUrl
    ) {
        super(
                id,
                title
        );

        if (
                content == null
                || content.isBlank()
        ) {
            throw new IllegalArgumentException(
                    "Article content is required."
            );
        }

        this.content =
                content.strip();

        this.downloadUrl =
                downloadUrl == null
                        ? ""
                        : downloadUrl.strip();
    }

    @Override
    public int calculateEstimatedMinutes() {
        int wordCount =
                content.split(
                        "\\s+"
                ).length;

        return Math.max(
                1,
                wordCount
                / WORDS_PER_MINUTE
        );
    }

    @Override
    public String getContentType() {
        return "ARTICLE";
    }

    @Override
    protected boolean isReadyForPublication() {
        return content.length()
                >= 20;
    }

    @Override
    public String getDownloadUrl() {
        return downloadUrl;
    }
}

QuizLesson.java

public final class QuizLesson
        extends ContentItem
        implements Gradable {

    private static final int MINUTES_PER_QUESTION =
            2;

    private final int questionCount;
    private final int passingScore;

    public QuizLesson(
            long id,
            String title,
            int questionCount,
            int passingScore
    ) {
        super(
                id,
                title
        );

        if (questionCount <= 0) {
            throw new IllegalArgumentException(
                    "Question count must be positive."
            );
        }

        if (
                passingScore < 0
                || passingScore > 100
        ) {
            throw new IllegalArgumentException(
                    "Passing score must be between 0 and 100."
            );
        }

        this.questionCount =
                questionCount;

        this.passingScore =
                passingScore;
    }

    @Override
    public int calculateEstimatedMinutes() {
        return questionCount
                * MINUTES_PER_QUESTION;
    }

    @Override
    public String getContentType() {
        return "QUIZ";
    }

    @Override
    protected boolean isReadyForPublication() {
        return questionCount > 0;
    }

    @Override
    public int calculateScore(
            int correctAnswers
    ) {
        if (
                correctAnswers < 0
                || correctAnswers > questionCount
        ) {
            throw new IllegalArgumentException(
                    "Correct answer count is invalid."
            );
        }

        return correctAnswers
                * 100
                / questionCount;
    }

    @Override
    public boolean hasPassed(
            int correctAnswers
    ) {
        return calculateScore(
                correctAnswers
        ) >= passingScore;
    }
}

Main.java

public class Main {

    public static void main(
            String[] args
    ) {
        ContentItem video =
                new VideoLesson(
                        1L,
                        "Abstract Classes",
                        "https://cdn.liveklass.io/video/abstract",
                        18
                );

        ContentItem article =
                new ArticleLesson(
                        2L,
                        "Interfaces",
                        "Interfaces define behavioral contracts for Java classes.",
                        "https://cdn.liveklass.io/articles/interfaces.pdf"
                );

        QuizLesson quiz =
                new QuizLesson(
                        3L,
                        "Abstraction Assessment",
                        10,
                        70
                );

        video.publish();
        article.publish();
        quiz.publish();

        printContent(
                video
        );

        printContent(
                article
        );

        printContent(
                quiz
        );

        printDownload(
                (Downloadable) video
        );

        printDownload(
                (Downloadable) article
        );

        printGrade(
                quiz,
                8
        );
    }

    private static void printContent(
            ContentItem content
    ) {
        System.out.println(
                content.getContentType()
                + ": "
                + content.getTitle()
        );

        System.out.println(
                "Estimated minutes: "
                + content
                        .calculateEstimatedMinutes()
        );

        System.out.println(
                "Published: "
                + content.isPublished()
        );

        System.out.println();
    }

    private static void printDownload(
            Downloadable downloadable
    ) {
        System.out.println(
                "Download available: "
                + downloadable
                        .hasDownloadAvailable()
        );

        System.out.println(
                "Download URL: "
                + downloadable
                        .getDownloadUrl()
        );

        System.out.println();
    }

    private static void printGrade(
            Gradable gradable,
            int correctAnswers
    ) {
        System.out.println(
                "Score: "
                + gradable.calculateScore(
                        correctAnswers
                )
        );

        System.out.println(
                "Passed: "
                + gradable.hasPassed(
                        correctAnswers
                )
        );
    }
}

Possible output:

VIDEO: Abstract Classes
Estimated minutes: 18
Published: true

ARTICLE: Interfaces
Estimated minutes: 1
Published: true

QUIZ: Abstraction Assessment
Estimated minutes: 20
Published: true

Download available: true
Download URL: https://cdn.liveklass.io/video/abstract

Download available: true
Download URL: https://cdn.liveklass.io/articles/interfaces.pdf

Score: 80
Passed: true

Avoid Unnecessary Casting in Real Design

Previous Main used:

printDownload(
        (Downloadable) video
);

কারণ variable compile-time type ছিল:

ContentItem

Better design যখন downloadable behavior প্রয়োজন, তখন reference শুরু থেকেই interface type হতে পারে।

Downloadable downloadableVideo =
        new VideoLesson(...);

অথবা method call-এর আগে concrete variable রাখা যায়।

VideoLesson video =
        new VideoLesson(...);

printContent(video);
printDownload(video);

Repeated casting avoid করা ভালো।

Polymorphic methods এবং collections পরবর্তী lesson-এ বিস্তারিত শেখানো হবে।


Design Decision: Abstract Parent or Interface Only?

Could we remove ContentItem and use interfaces only?

Possible:

public interface ContentItem {

    long getId();

    String getTitle();

    int calculateEstimatedMinutes();
}

Then each class independently state store করবে।

This may be appropriate if:

  • Shared state নেই
  • Shared constructor rules নেই
  • Implementations unrelated
  • Multiple class inheritance freedom প্রয়োজন

But current domain-এ:

id
title
published
publication lifecycle

সত্যিকার অর্থে shared।

তাই abstract class reasonable।


Design Decision: Abstract Class Only?

Could Downloadable be parent method?

public abstract String getDownloadUrl();

Then every content type download support করতে বাধ্য হবে।

Quiz lesson যদি downloadable না হয়, hierarchy invalid contract impose করবে।

Capability interface better।


Engineering Note: Abstraction Has a Cost

Each abstract class বা interface introduces:

  • New concept
  • New name
  • New dependency
  • More files
  • More navigation
  • More contracts to understand
  • Potential compatibility obligations

Use abstraction when it removes meaningful coupling or expresses a real model।

Do not create abstractions only because:

“Enterprise code should have interfaces.”

Common Mistakes

Giving an Abstract Method a Body

public abstract int calculate() {
    return 0;
}

Invalid।


Instantiating an Abstract Class

new ContentItem(...)

Invalid।


Forgetting to Implement Abstract Methods

Concrete child compile করবে না।


Making an Interface Implementation Non-Public

Interface methods public contract।

Implementation visibility reduce করা যায় না।


Using an Abstract Class Only for Constants

Abstract class inheritance model-এর জন্য।


Creating an Interface for Every Concrete Class

Real substitutability না থাকলে unnecessary abstraction।


Putting Shared Mutable State in an Interface

Interface instance state own করে না।


Forcing Every Child to Support Every Capability

Download capability separate interface হওয়া উচিত যদি সব content downloadable না হয়।


Using Marker Interfaces Without a Real Need

Empty type markers often annotation বা explicit property দিয়ে clearer হতে পারে।


Overusing Default Methods

Interface gradually shared implementation-heavy abstract class-এর substitute হয়ে যেতে পারে।

Default methods small contract-related behavior-এর জন্য রাখুন।


Creating Deep Abstract Hierarchies

ContentItem
→ MediaContent
→ DownloadableMedia
→ TimedMedia
→ VideoLesson

প্রতিটি layer justified না হলে complexity বাড়ে।


Practice Exercises

Exercise 1: Make ContentItem Abstract

Existing concrete parentকে abstract করুন।

Add:

public abstract int calculateEstimatedMinutes();

public abstract String getContentType();

Verify করুন direct instantiation compile করে না।


Exercise 2: Create Completable

Define:

public interface Completable {

    boolean complete();

    boolean isCompleted();
}

Decide which content types should implement it।

Explain whether completion state content object-এর নাকি learner progress object-এর responsibility।


Exercise 3: Create Downloadable

Implement in:

VideoLesson
ArticleLesson

Do not implement in QuizLesson unless domain requirement supports it।


Exercise 4: Abstract or Interface?

Choose an appropriate abstraction:

  1. All lesson types share ID, title, publication state
  2. Some content can be downloaded
  3. Quiz and assignment can be graded
  4. Email and SMS can send notifications
  5. All prices have amount and currency

Possible choices:

Abstract class
Interface
Immutable value object

Explain each।


Exercise 5: Find the Broad Contract

Review:

public abstract class ContentItem {

    public abstract void download();

    public abstract int calculateScore();
}

Explain why this parent contract is too broad।

Refactor with capability interfaces।


Exercise 6: Default Method

Add to Downloadable:

default boolean hasDownloadAvailable()

Use getDownloadUrl() to calculate the result।


Exercise 7: Prevent Invalid Publication Flow

Create abstract:

protected abstract boolean isReadyForPublication();

Keep parent:

public final boolean publish()

Implement different readiness rules in video and article lessons।


Predict the Result

Question 1

public abstract class ContentItem {

    public abstract int calculate();
}

Can this compile?

new ContentItem();

Question 2

public class VideoLesson
        extends ContentItem {

}

Will it compile if VideoLesson is concrete and does not implement calculate()?


Question 3

public interface Downloadable {

    String getDownloadUrl();
}

Can implementation be:

protected String getDownloadUrl() {
    return url;
}

Question 4

Can a class extend one abstract class and implement two interfaces?


Question 5

Can an abstract class contain a fully implemented method?


Question 6

Can an interface contain a default method with a body?


Predict the Result Answers

Answer 1

না।

Abstract class directly instantiate করা যায় না।

Answer 2

না।

Concrete child required abstract method implement করতে হবে।

Answer 3

না।

Interface method public contract। Implementation public হতে হবে।

Answer 4

হ্যাঁ।

class QuizLesson
        extends ContentItem
        implements Gradable,
                   Completable

Answer 5

হ্যাঁ।

Abstract class concrete এবং abstract methods দুটোই রাখতে পারে।

Answer 6

হ্যাঁ।

Modern Java interface default method support করে।


Knowledge Check

Question 1

Abstract class কী?

Question 2

Abstract method কী?

Question 3

Abstract class instantiate করা যায় না কেন?

Question 4

Abstract class constructor রাখতে পারে কি?

Question 5

Concrete child abstract method implement না করলে কী হয়?

Question 6

Interface কী represent করে?

Question 7

implements কী করে?

Question 8

একটি class কয়টি interfaces implement করতে পারে?

Question 9

Interface method implementation public হতে হয় কেন?

Question 10

Abstract class এবং interface-এর main difference কী?

Question 11

Interface field কী ধরনের member হয়?

Question 12

Default method কী?

Question 13

Abstract class এবং interface একসঙ্গে ব্যবহার করা যায় কি?

Question 14

Every class-এর interface প্রয়োজন কি?

Question 15

Capability interface কখন useful?


Knowledge Check Answers

Answer 1

একটি incomplete base class, যা shared state ও behavior রাখতে পারে এবং direct instantiate করা যায় না।

Answer 2

Implementation ছাড়া declared method, যা concrete childকে implement করতে হয়।

Answer 3

Classটি complete concrete object contract provide করে না।

Answer 4

হ্যাঁ। Constructor child object-এর parent state initialize করে।

Answer 5

Compile error হয়, unless child classও abstract হয়।

Answer 6

একটি behavioral contract বা capability।

Answer 7

Classকে interface contract গ্রহণ এবং implement করতে বলে।

Answer 8

Multiple।

Answer 9

Interface method external public contract হিসেবে defined।

Answer 10

Abstract class shared state, constructor এবং base implementation রাখতে পারে। Interface flexible capability contract define করে এবং multiple implement করা যায়।

Answer 11

Implicitly public static final constant।

Answer 12

Interface-এর concrete method, যা implementations inherit বা override করতে পারে।

Answer 13

হ্যাঁ।

Answer 14

না। Real substitutability বা boundary না থাকলে interface unnecessary হতে পারে।

Answer 15

যখন কিছু types একটি behavior support করে কিন্তু same base class share করা প্রয়োজন নেই।


Lesson Summary

এই lesson-এ আমরা শিখেছি:

  • Meaningless parent default behavior invalid state hide করতে পারে
  • Abstract method required specialization enforce করে
  • Abstract class direct instantiate করা যায় না
  • Abstract class shared fields, constructors এবং concrete methods রাখতে পারে
  • Abstract constructor child object-এর parent state initialize করে
  • Concrete child required abstract methods implement করে
  • Abstract child implementation defer করতে পারে
  • Parent shared algorithm এবং child-specific step combine করতে পারে
  • Final template method parent invariant protect করতে পারে
  • Interface behavioral contract বা capability represent করে
  • Class implements দিয়ে interface গ্রহণ করে
  • Interface methods public contract
  • একটি class multiple interfaces implement করতে পারে
  • Interface references implementation-independent polymorphism দেয়
  • Abstract class shared identity এবং state-এর জন্য useful
  • Interface shared capability এবং replaceable behavior-এর জন্য useful
  • Interface fields instance state নয়; constants
  • Modern interfaces default, static এবং private helper methods রাখতে পারে
  • Default method conflict হলে classকে resolve করতে হয়
  • Abstract class একটি interface implement করতে পারে
  • একই class abstract parent extend এবং multiple interfaces implement করতে পারে
  • Broad parent contract unsupported child behavior force করতে পারে
  • Capability interfaces broad hierarchy avoid করতে সাহায্য করে
  • Every class-এর interface তৈরি করা প্রয়োজন নেই
  • Interface explosion codebase fragmented করতে পারে
  • Empty abstract parent বা marker interface meaningful abstraction নাও হতে পারে
  • Abstraction real domain বা dependency need থেকে আসা উচিত
  • Abstract class এবং interface complementary tools, competitors নয়

Next Lesson

পরবর্তী lesson:

Polymorphic Methods and Collections

আমরা শিখব:

  • Parent এবং interface type parameters
  • Multiple implementations একই method-এ pass করা
  • Polymorphic collections
  • Runtime dispatch inside loops
  • Common operations without type-specific conditions
  • Safe casting
  • Pattern matching with instanceof
  • Casting কখন necessary
  • Repeated type checks কখন design smell
  • Polymorphic return values