Design Pattern trong Dart: Composite Pattern

The Composite Pattern is one of the most intuitive and useful Structural Design Patterns — especially when working with tree-like structures, like Flutter widgets, file systems, or nested UI components.

Here’s your full English-language blog post for the Composite Pattern in Dart, including clear explanations, a tree-like example, and runnable code — perfect for your readers.


Design Patterns in Dart: Composite Pattern

What is the Composite Pattern?

The Composite Pattern is a structural pattern that lets you treat individual objects and groups of objects uniformly.

In simpler terms:

“Compose objects into tree structures and work with them as if they were individual objects.”

It’s perfect when you need to deal with part–whole hierarchies like:

  • File/folder systems,
  • Nested UI components,
  • Scenes in game engines.

When to Use the Composite Pattern?

  • When you need to treat single objects and collections the same way.
  • When building recursive structures (tree, folder, UI layout).
  • When you want to simplify complex structures by using the same interface.

Real-World Analogy

Think of a company organizational chart:
A manager may have subordinates — but those subordinates may be managers themselves, with their own subordinates.

You can:

  • Treat a single employee (leaf)
  • Or a manager (composite)
    → in the same way via a shared interface.

Example in Dart: File System Hierarchy

We’ll simulate a file system with File and Directory.
Each Directory can contain both File and other Directory objects.


Step 1: Define the Component Interface

abstract class FileSystemEntity {
void display([int depth = 0]);
}

Step 2: Create Leaf Nodes (File)

class File implements FileSystemEntity {
final String name;

File(this.name);

@override
void display([int depth = 0]) {
print('${' ' * depth}- File: $name');
}
}

Step 3: Create Composite Nodes (Directory)

class Directory implements FileSystemEntity {
final String name;
final List<FileSystemEntity> _children = [];

Directory(this.name);

void add(FileSystemEntity entity) {
_children.add(entity);
}

void remove(FileSystemEntity entity) {
_children.remove(entity);
}

@override
void display([int depth = 0]) {
print('${' ' * depth}+ Directory: $name');
for (var child in _children) {
child.display(depth + 1);
}
}
}

Step 4: Client Code

void main() {
var root = Directory("root");
var home = Directory("home");
var docs = Directory("docs");

root.add(File("README.md"));
root.add(home);

home.add(File("user.txt"));
home.add(docs);

docs.add(File("notes.txt"));
docs.add(File("todo.txt"));

root.display();
}

🧪 Output:

+ Directory: root
- File: README.md
+ Directory: home
- File: user.txt
+ Directory: docs
- File: notes.txt
- File: todo.txt

Explanation

  • FileSystemEntity is the common interface.
  • File is a leaf node — has no children.
  • Directory is a composite — contains other FileSystemEntity instances.
  • Both leaf and composite share the same method: display(), allowing recursive traversal.

Benefits of Composite Pattern

  • Uniform treatment of individual and grouped objects.
  • Supports recursive structures like trees, UIs, file systems.
  • Simplifies client code — no need to check whether it’s a leaf or composite.
  • Easy to add new components.

Drawbacks

  • Can make the design overly generalized or abstract.
  • Might introduce unnecessary complexity for simple structures.
  • Harder to enforce constraints (e.g., directory must only contain files).

Flutter Use Cases

Flutter uses the Composite Pattern extensively:

  • Widgets are nested inside widgets (like Column, Row, Stack, etc.)
  • Widget is the component.
    • Text, Image, Button → Leaf widgets
    • Container, Column, ListView → Composite widgets
  • You treat them the same because they all extend from Widget.

Summary Table

AttributeComposite Pattern
PurposeTreat single and group objects uniformly
Common Use CasesWidget trees, file systems, UI layout
Easy in Dart?Yes, with inheritance & recursion
Useful in Flutter?Fundamental to the widget tree

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Lên đầu trang