Mobile Development 11 min read

Why Composition Beats Inheritance in Android List Refactoring

This article explains how refactoring the Baixing Android app’s list feature from an inheritance-heavy design to a composition-based architecture improves modularity, reduces coupling, and eases future extensions by applying OOP principles such as dependency inversion and component interfaces.

Baixing.com Technical Team
Baixing.com Technical Team
Baixing.com Technical Team
Why Composition Beats Inheritance in Android List Refactoring
One key OOP principle is to prefer composition over inheritance. While inheritance lets a subclass reuse parent code, it tightly couples the child to the parent, breaking encapsulation and making maintenance harder as the hierarchy grows. This article reviews the refactoring of the Baixing Android app’s list feature to illustrate how we applied this principle in practice.

Background

In the early Baixing Android app, list functionality was simple: fetch data from the server and render it. Initially we used an inheritance‑based structure, placing data loading and UI rendering logic in a common parent class.

In this article, the Chinese term “list” refers to a Fragment composed of List, FilterBar, BottomBar, etc., while the English “List” specifically denotes the UI List control. BaseListFragment is the parent of all list fragments, encapsulating shared data‑loading and UI‑rendering logic. Subclasses such as ListFragmentWithFilterBar extend it to add specific features like a filter bar.

As requirements grew, the inheritance tree became deep and unwieldy. Adding new features meant creating more subclasses, leading to a bloated hierarchy where changes to the parent affected all children.

When a new data‑loading method was needed, we faced two inheritance‑based options: modify BaseListFragment directly (risking a massive, hard‑to‑maintain parent) or create a new parent class (duplicating code across parallel hierarchies). Both approaches increased coupling and maintenance effort.

From Inheritance to Composition

Composition preserves encapsulation because components interact only through well‑designed interfaces, keeping each part a “black box.” It also adds flexibility: different component implementations can be swapped without affecting the overall structure, and composition can be decided at runtime.

Applying the Dependency Inversion Principle, we program to abstractions rather than concrete implementations. A list is built from components such as List, FilterBar, and BottomBar, each defined by an interface (e.g., IList, IFilterBar) that extends a common IComponent interface.

Different concrete implementations (e.g., List1 vs. List2) can be selected by a fragment at runtime, reducing coupling and allowing flexible assembly of list variants.

Implementation in Android

1. Components

Each component is essentially a wrapper around an Android View. The component interfaces inherit from IComponent, which mirrors the fragment lifecycle methods.

Components encapsulate their own lifecycle logic (e.g., binding a LayoutManager after view creation, releasing resources on onDestroyView), making them reusable across different fragments.

2. New BaseListFragment

The new BaseListFragment no longer knows which components it contains; subclasses register their component instances in a Map that maps view IDs to IComponent objects. During each fragment lifecycle callback, BaseListFragment iterates over this map and forwards the call to every component.

Subclasses must:

Specify their layout.

Create required components and register them with the view‑ID map.

Establish interactions between components (e.g., let FilterBar trigger a refresh on List).

This composition‑based design keeps the inheritance depth to a single level, improves flexibility, and makes future feature changes easier to manage.

Conclusion

The refactoring demonstrates that replacing deep inheritance with composition reduces coupling, enhances maintainability, and allows rapid adaptation to new requirements. Understanding and applying design‑pattern principles in real projects helps developers internalize these concepts.

interface IComponent {
    void onCreate(Bundle savedInstanceState);
    void onCreateView(View view);
    void onSaveInstanceState(Bundle outState);
    void onResume();
    // ... other lifecycle methods
    void onDestroy();
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Design PatternsComponent ArchitecturerefactoringDependency InversionComposition over Inheritance
Baixing.com Technical Team
Written by

Baixing.com Technical Team

A collection of the Baixing.com tech team's insights and learnings, featuring one weekly technical article worth following.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.