オブジェクト指向プログラミング
人間として、私たちは常に、理解しなくてはならない無数の事実と無数の印象に向き合っています。そうする上で、表面にある細々としたもので隠れた仕組みを抽象化*して、作用している基本的な関連性を見つけ出さなくてはなりません。抽象化するとは原因と結果を明らかにし、パターンとフレームワーク**を抽出し、そして重要でないものから重要なものを選び上げることです。オブジェクト指向は、あなたが操作するデータの抽象化を提供します。そのうえ、データと、あなたがデータへ施す操作ーこれは実質的にはデータの振る舞いを提供ーこの2つの間を具体的にグループへ分ける作業を提供します。(*abstract, アブストラクト)(**framework, 体系)
データと操作*
(*operations, オペレーション)
プログラミング言語は伝統的に世界を二つに分けています。データとデータの操作です。データは静的で不変です、なにかの操作がそれを変えようとしない限りは。データを操作する手続きなり関数は、永続的な状態はないというデータを操作するものです。これら手続きや関数は、データへ影響を与えるという点でのみ役立ちます。
もちろん、この分け方はコンピュータ動作に由来するものなので、これを無視したりわきへ置いておけます。しかしこれは、たとえば物質とエネルギー、名詞と動詞といった、たいていの人が分かる区別と同じように、私たちが何かをする基礎を形作っています。同じようにして、すべてのプログラマ、オブジェクト指向のプログラマでさえも、プログラムが使うデータの構造をレイアウト*し、そのデータへ働きかける関数を定義しなくてはなりません。(*lay out, (動詞)適切に配置する)
Cのような手続き型のプログラミング言語では、それらがすべてです。これら言語は、データと関数を構成するためにさまざまな種類の支援していますが、その世界をほかの方法で分類しようとはしません。関数とデータ構造は、設計における基本的となる要素です。
オブジェクト指向のプログラミングは、そのような考え方に強く異論を唱えることなく、世界の見え方をより高いレベルへと作り替えています。操作とデータをオブジェクトと呼ばれるモジュラユニットへまとめ上げ、オブジェクトを組み合わせて構造化されたネットワークを作り、完全なプログラムとします。オブジェクト指向のプログラミング言語では、オブジェクト自身とオブジェクト間の相互作用がデザインの基本となる要素です。
すべてのオブジェクトは、状態(データ)と振る舞い(データへの操作)の両方を持ちます。このやり方は、どこにでもある実体を持つ物体*とさほど変わりません。懐中時計やピアノのように、内部に状態と振る舞いを備え持つ機械的な装置がどのように動くのかは簡単に理解できます。考えてみれば、何かの役目をするよう設計されているほとんどのものは、すべてそのようなっています。たとえば、ビンのように何も動く部分を持たない簡単なものさえ、状態(どれぐらいビンに入っているか、開けられているかどうか、その内容物はどれぐらい温められているか)は動作(さまざまな流速で内容物を流し出せるかの能力、開いている、閉まっている、高温または低温にどれぐらい耐えるかといった能力)を備えています。(*object, オブジェクト)
この、実際の物体との類似性こそが、オブジェクトに大きな力と理解のしやすさを実現しています。オブジェクトは現実世界のシステムにある要素をモデル化するだけではなく、それと同時にソフトウェアシステムの中にある要素へ役割を割り振っています。
インターフェイスと実装
プログラムを創り出すには、抽象的な概念を見つけ出し、それらをプログラムデザインの中で表現しなくてはなりません。これの助けになるのがプログラミング言語の役割です。プログラミング言語は創作とデザインの過程を分かりやすくするもので、ものが動作する方法を明らかにするさまを抽象化してコードへ書き出すように促すことで達成されます。これは、あなたのアイディアをコードの中で実現できるようにします。表面の細々したものは、プログラムのアーキテクチャーを良く分からないものにすべきではありません。
すべてのプログラミング言語は、抽象的な概念を表現する助けとなる仕組みを提供しています。本質的に、それら仕組みは、実装の詳細をグループ分けし、それらを隠し、少なくともある程度までは共通のインターフェイスを与えます。このことは、機械的なオブジェクトが、内部実装からインターフェイスを分けているのによく似てます。その例をFigure 2-1に示します。
Figure 2-1 インターフェイスと実装
このようなユニットの内側を見ると、制作者の視点、何で成り立っているかと、どのように働くかに関心を持つでしょう。これを外側から見ると、使用者の視点、これは何なのか、何の働きがあるかにのみ関心を持つでしょう。詳細のことは考えもせず、高いレベルでこのユニットがどのような働きをするかのみを考えることができます。
C言語で抽象的概念の単位は、構造体と関数です。このどちらも、やり方は違いますが、実装の要素を隠します。
この世界のデータ側では、Cの構造体は、データ要素を大きな単位へグループ分けし、一つのエンティティをして扱えるようになります。コードは複雑な構造体の内部へ潜り込み個々のフィールドを操作しなくてはなりませんが、ほとんどのプログラムでは構造体を一つのものと見なします。要素のコレクションとではなく、要素が一緒になって表現されているものとしています。一つの構造体は他のものを取り込めるので、とてもシンプルなレイヤーの組み合わせから情報の複雑な塊ができてしまします。
現代的なCにおいては、構造体のフィールドは自身の名前空間にあります。つまり、それぞれの名前は構造体の外にある同じ名前のデータ要素と衝突することはありません。プログラムで名前空間を区分けするのは、本質的には、実装の詳細がインターフェイスの外側へ露出しないようにするためです。たとえるなら、大きなプログラムで個々の部分へそれぞれ異なった名前を付け、その新しい名前がそれまであったものと衝突しないかどうか確かめるような途方もない仕事を想像してみてください。
この世界の手続き側では、関数は再定義されることなく繰り返しつかえる振る舞いをカプセル化*します。関数への局所的なデータ要素は、たとえば構造体の中のフィールドのように、それら固有の名前空間の中で保護されています。関数はほかの関数を参照する(呼び出し)できるので、小さなものから複雑な振る舞いができてしまいます。(*encapsulate, 隠蔽する)
関数は再利用ができます。一度定義されれば、実装が何であったかをもう一度考えることなく、何回でも呼び出せます。一般的に、最も便利な関数は、ライブラリから取ってきて、色々なアプリケーションで再利用できるものです。利用する側のユーザが必要なのは、関数のインターフェイスで、そのソースコードではありません。
しかし、データ要素とは異なり、関数は独自の名前空間へ区分けできません。どの関数も唯一の名前を持たなくてはなりません。関数は再利用できますが、名前はそうはいきません(*名前までは再利用できません)。
Cの構造体と関数は、相当深い抽象的な概念を表せますが、データとデータ操作とを明確に違うものとして保持します。手続き型プログラミングにおいて、抽象化の第上位の単位はそれらどちらか、データなのか操作なのかの区分でしか存在できません。
オブジェクト指向のプログラミングでは、データ構造と関数どちらの長所も失いません。もう一歩進めて、高い位置にある抽象概念を可能とする単位、関数とそれが保持するデータの間で行われる相互作用を隠す単位を加えていています。
たとえば、一つ特定なデータ構造へ作用するいくつかの関数群があったとします。それら関数を使いやすいものとしたいと考え、可能な限りで、インターフェイスの外へ構造体を取り出したとします。するとデータを管理するさらなる関数を補充します。データ構造を操作するすべての仕事ーメモリを割り振り、初期化し、情報を取得し、値を変更し、更新し続け、メモリを解放するーこれらを関数群を通して実行します。この関数のユーザがすることすべては、関数を呼び出し、それに構造体を渡すことです。
そのような変更を受けると、構造体は、ほかのプログラマが決して内部を見たりしない不透明なものになってしまいます。彼らは関数が何をするのか、どうやってデータが形作られているかに気を配らなければなりません。それに対して、あなたはオブジェクトを作ろうとしている最初のステップを踏み出そうとしています。
つぎのステップは、この考え方をプログラミング言語において支持させて、関数の間で受け渡す必要がないとしてデータ構造を完璧に隠すことです。データは内部的な実装の一部になります、ユーザへ見せるのは関数インターフェイスだけです。オブジェクトは完璧にそのデータをカプセル化(隠蔽)するので、ユーザはそれらの振る舞いのみを考えることができます。
このステップによって、関数へのインターフェイスは一層簡単なものになります。呼び出し側はどうやって実装されているか(どんなデータを使用しているのか)を知る必要はありません。まさにこれをオブジェクトと呼びます。
隠したデータ構造は、それへのアクセスを共有するすべての関数を一体にします。したがって、一つのオブジェクトは、行き当たりばったりの関数ひとかたまりを超えるものです。そのオブジェクトは、共有されたデータで支えられた振る舞いを束ねたものです。オブジェクトに属している関数を使うには、まず最初にオブジェクトを生成し(このことはオブジェクトにその内部向けのデータ構造をあたえ)、それからオブジェクトにどの関数を実行すべきか伝えます。個々の関数について考えるのではなく、オブジェクトが何をするのかという観点から考え始めます。
このように、関数とデータ構造について考えることから、オブジェクトの動作についてと考えるへと発展させるのは、オブジェクト指向のプログラミングを学ぶことの本質です。最初は馴染みがないかもしれませんが、オブジェクト指向のプログラミングの経験を積むにつれて、この方法は事柄を考えるのにより自然な方法の一つだとわかります。ありふれたプログラミング用語は、現実社会のさまざまなオブジェクトへの類似していると考えられます。リスト、コンテナ、テーブル、コントローラ、そしてマネージャにしても。そのようなものをプログラミング可能なオブジェクトとして実装するのは、自然な方法で類似性を拡げているに過ぎません。
プログラミング言語は、コードとしてプログラミングできる様々な種類の抽象概念で良し悪しが見分けられています。本質的でない事柄に気を取られたり、とらえようとしている真実に合わない用語で無理に表現しないべきでしょう。
たとえば、データは正確で、それに対応する手続きも正確となるように保守しなくてはならないとしたら、全体のプログラムの低レベルの実装にまで常に気を配るのを強いられます。高いレベルの抽象概念でプログラムを作成し続けたいにもかかわらず、発想から実装へいたる道はひどく弱々しいものになり、それはさらにプログラムが大きくまたより複雑なものになるにつれて、一層と実現が不可能のものとなっていきます。
これとは違う、より高いレベルでの抽象概念によって、オブジェクト指向のプログラミングは豊富な語彙とプログラムへ埋め込める多様なモデルを提供しています。
Referred from
Object-Oriented Programming with Objective-C, Why Objective-C?
Copyright
Copyright © 201 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2010-11-15