委任による合成の合成



ステージの設定
任意のアプリケーションは、複数のコンポーネントから構成されます-オブジェクト指向言語では、典型的にはクラスです.時々、これらのクラスも一緒に働く!これらのクラスの外部ユーザーは、舞台裏で、より多くのクラスが一緒に働いているということを知らないかもしれません.パブリックAPIは、彼らがそれを必要とするものを行います.しかし、これらの異なるクラスの特殊化を維持するが、一緒にそれらを使用して、有益です.
複合システムをモデル化して、その構成に委任を使用するために合成物を使用することを実証するために、我々はシンセサイザーがどのように音のプリセットを記憶するためにメモリ管理を扱うことができるかについて調査します.この例はRubyConf 2020 ルビーの話Coverage モジュールです.

騒音低減
The synthesizer 楽器は音の広い配列を生成することができます.サウンドとエフェクトのコレクションは、パッチとして知られています.
class Patch
  attr_reader :sound
  attr_reader :effect
  attr_reader :filter
  attr_reader :oscillator
end
あなたはシンセサイザのメモリ上でこれらのパッチを保存し、後で簡単にアクセスするためにそれらを思い出すことができます.
patch = Patch.new
synth = Synthesizer.new

synth.save_patch(location: :b1, patch: patch)
synth.set_patch(patch)
synth.play_key(note: :a, duration: 1)

迷惑をかけなさい
実際の楽器と同じように様々なサブコンポーネントから構成されていますSynthesizer 専門知識の分野に特化した様々なクラスで構成されています.
たとえば、上記のシンセサイザは、そのボードメモリにパッチを保存する方法を知りません.それはそれを扱うためにそのパッチメモリに頼ります.
class Synthesizer
  def save_patch(location:, patch:)
    @patch_memory.write(location: location, patch: patch)
  end
end
シンセサイザー自体が知っているすべてのものは、それをするためにメモリに送るメッセージです.シンセサイザはパッチメモリインスタンスにこれらのパッチを格納する責任を委任しています.
シンセサイザーを演奏している誰でも、それがどのようにこれらのパッチを保存しているかについて心配する必要はありません.シンセサイザークラスを使用している誰でも、シンセサイザーが使用している別々のパッチメモリクラスがあるということを知りません.
同時に、我々のシンセサイザは、直接そのメモリにアクセスする方法を知りません.それはPatchMemory そのクラスに対するメモリ管理関連の責任を委任します.サンディメッツとしてPractical Object-Oriented Design In Ruby , シンセサイザは、それが他の部分のシリーズを有するので、パッチ記憶装置を有する.そして、それらはシンセサイザ
提供する

代表への重要な利益
デリゲートは、複雑なシステムを簡単に絞り込むようにする重要なドライバをいくつか提供します.

特殊化
我々のパッチ・メモリ構成要素は、それが保存されて、格納された音を思い出す所である器具の機上記憶装置とのインターフェースに単独で集中しています.そのテストは、すべてのエッジのケースとminutiaeのために考慮する必要が掘ることができます.実装は非常に具体的な意思決定を行うことができますので、それは非常に効果的なシステムの他の領域なしで心配する必要があります.
シンセサイザー自体は複雑なシステムです.メモリ管理は1つだけの小さな部分です.我々の強さと価値Synthesizer クラスは、すべてのこれらのコンポーネントのすべてを整理し、それらに渡すために正しいメッセージを知って、そのすべての詳細の親密な知識を必要としないパブリックAPIを使用しています.我々の内部のならばSynthesizer クラスはこの責任そのものをすべて取り扱っていたが、それはすぐに扱いにくく、操縦が困難になるだろう.
読むのは難しい、トラブルシューティングへの挑戦、テストする負担、および変更が必要なときに恐れた.

柔軟性と再利用
実際には、さまざまな種類のシンセサイザーがあります.いくつかのボード上の1000種類のパッチを格納することができます.他の4つだけの容量を持つことがあります.さらに多くの場合は、ほぼ無限のストレージのためのUSBデバイスをプラグインすることができます拡張メモリを持っている可能性があります.
代わりに、これらのシナリオのいずれかを処理するために全く別のシンセサイザークラスを作成する必要があるのではなく、代わりに、パッチメモリクラスの違いをモデル化する必要があるだけです.私たちのシンセサイザーは、それらのいずれかを使用することができますし、まだ別のクラス間で重複を必要とせずに、その機能の残りの部分を維持します.
これでexample , 我々のシンセサイザーは、それのブランドに基づいてその記憶能力を変えます.
def initialize_memory
  if @brand == :moog
    @patch_memory = MoogPatchMemory.new
  elsif @brand == :nord
    @patch_memory = NordPatchMemory.new
  end
end
おかげで、これらのパッチメモリクラスが同じメッセージに応答する限りSynthesizer クラスは交換可能です.

ロックオン
一緒にクラスを作成すると、完全に機能するシステムを作成することができます.要求または責任を処理するために別のクラスを使用するクラスは、ヘルパークラスにその義務を委任することです.委任は、外部のなしでコード組織のために異なる専門知識の知識をカプセル化することができます
消費者は知っているか、その実現詳細について気にする必要があります.異なったクラスに責任を委任することはまた、システムが変わるのをより簡単にすることができます.そして、それがコード再利用を促進する可能性がより高くなります.
次に、私たちはソフトウェア設計における最大のヒットの一つを演じるつもりです.

This post originally published on The Gnar Company blog.