@nqounetです。
いよいよ最終回です。前回までに、様々なフィルターを実装してパイプラインを構築してきました。今回は、プラグイン機構を導入して、外部からカスタムフィルターを動的に読み込めるようにします。
このシリーズについて
なぜプラグイン機構が必要なのか
これまでに作成したフィルターは以下の通りです。
- GrepFilter
- SortFilter
- UniqFilter
- CountFilter
- StatsFilter
- ExtractFilter
- AccessLogParser
- FieldFilter
- StatusFilter
- TopNFilter
すでに10種類ものフィルターがあります。しかし、実際の業務ではさらに多くのフィルターが必要になるでしょう。
- Nginx専用のログパーサー
- JSONログのパーサー
- 特定のビジネスロジックに基づくフィルター
- 社内独自フォーマットの変換フィルター
これらすべてをパイプラインのコア部分に組み込んでいたら、コードは肥大化し、保守が困難になります。
解決策は、フィルターをプラグインとして外部化し、必要なものだけを動的に読み込む仕組みを作ることです。
プラグインローダーの設計
プラグインは以下の規約に従うものとします。
Pipeline::Plugin::Xxxという名前空間を持つFilterクラスを継承している- 特定のディレクトリに配置されている
これに基づいてプラグインローダーを実装します。

| |
プラグインの例:JsonLogParser
JSONフォーマットのログを解析するプラグインを作成してみましょう。
plugins/JsonLogParser.pm:
| |
プラグインの例:UpperCaseFilter
テキストを大文字に変換するシンプルなプラグインです。
plugins/UpperCaseFilter.pm:
| |
プラグインをPipelineBuilderに統合
PipelineBuilderにプラグインを使うためのメソッドを追加します。
| |
プラグインを使ったパイプライン
| |
実行結果は以下の通りです。
| |
開放閉鎖の原則(OCP)の体現
プラグイン機構を導入したことで、開放閉鎖の原則(OCP)が完全に実現されました。
- 拡張に対して開いている:新しいプラグインを追加するだけで機能を拡張できる
- 修正に対して閉じている:コア部分のコードを変更する必要がない
flowchart TD
subgraph Core["コア(変更不要)"]
Filter["Filter基底クラス"]
Builder["PipelineBuilder"]
Loader["PluginLoader"]
end
subgraph Plugins["プラグイン(自由に追加)"]
P1["JsonLogParser"]
P2["UpperCaseFilter"]
P3["NginxLogParser"]
P4["CustomFilter"]
PN["..."]
end
Loader --> P1
Loader --> P2
Loader --> P3
Loader --> P4
Loader --> PN
新しい要件が発生しても、プラグインを追加するだけです。既存のコードには一切手を加えません。
シリーズ全体の振り返り
全6回を通じて、以下のことを学びました。
| 回 | テーマ | 学んだこと |
|---|---|---|
| 第1回 | 基礎 | Chain of Responsibilityパターン、GrepFilter |
| 第2回 | Decorator | 基底クラス、SortFilter、UniqFilter |
| 第3回 | ビルダー | Fluent Interface、PipelineBuilder |
| 第4回 | 集約 | Aggregator、CountFilter、StatsFilter |
| 第5回 | 実践 | アクセスログ解析、構造化データ処理 |
| 第6回 | プラグイン | 動的ロード、開放閉鎖の原則 |
2つのデザインパターン(Chain of ResponsibilityとDecorator)を組み合わせ、Unix哲学に基づいたモジュラーなテキスト処理システムを構築しました。
今回のポイント
- プラグイン機構の必要性と設計を学んだ
- PluginLoaderクラスで動的なモジュールロードを実装した
use_pluginメソッドでプラグインをパイプラインに統合した- 開放閉鎖の原則(OCP)が完全に実現された
今回の完成コード
以下が今回作成したコードの完成版です。
| |
おわりに
全6回を通じて、テキスト処理パイプラインを一から構築してきました。
Chain of ResponsibilityパターンとDecoratorパターンという、パイプライン処理と最も相性の良い2つのパターンを組み合わせることで、Unix哲学をオブジェクト指向で再現しました。
小さなフィルターを組み合わせて大きな処理を実現する。このアプローチは、Perlの伝統的な強みであるテキスト処理と完璧にマッチしています。
ぜひ、このシリーズで学んだ知識を活かして、自分だけのフィルターやパイプラインを作ってみてください。
お疲れ様でした!
