さよならオブジェクト指向プログラミング



私は何十年もの間、オブジェクト指向言語でプログラミングを行ってきました。 これらの最初はC ++、次にSmalltalk、最後に.NETとJavaでした。 オブジェクト指向プログラミングパラダイムの3つの柱である継承、カプセル化、ポリモーフィズムの利点を熱狂的に利用しました。 約束された再利用を活用し、この新しい刺激的な分野で前任者が蓄積した知恵に触れたいと思いました。 私は、現実世界のオブジェクトをクラスにマッピングできるという考えに不安を感じ、全世界をきちんと配置できると考えました。

私はこれ以上間違っているはずはありません。

継承-最初の倒れた柱




一見、継承はOOPパラダイムの主な利点です。 与えられた階層の単純化された例はすべて理にかなっているように見えました。



そして、「再利用」は一般的にその日の用語です。 おそらく一年も、それ以上もありません。 私はこれをすべて飲み込み、実際のプロジェクトで私の新たなビジョンを実現するために走りました。

バナナ、サル、ジャングルの問題


私の心への信仰と未解決の問題を抱えて、私はクラス階層を作成し、コードを書き始めました。 そして、世界は調和していた。 既存のクラスを継承することで再利用を最大限に活用しようとした日を決して忘れません。 私は長い間、この瞬間を待っていました。

新しいプロジェクトが登場しました。クラスでの私の考えを忘れず、とても熱心でした。 問題ありません。 急いで再利用してください。 別のプロジェクトからクラスを取得して適用するだけです。 まあ...実際には...ただのクラスではありません。 親クラスが必要です。 しかし...しかしそれだけです。 Ghm ...ちょっと待って...親の別の親が必要になるようです...そして...一般的に、すべての親が必要です。 良い...良い...私はそれを理解します。 問題ありません。

まあ、素晴らしい。 コンパイルしません。 なぜ??? ああ、なるほど... このオブジェクトにはこの他のオブジェクトが含まれています。 だから私も彼が必要です。 問題ありません。 待って...私はそのオブジェクトだけ必要としません。 私は彼の親、そして親の親などが必要です。 囲まれたオブジェクトごとに、親とその親、およびその親、親が必要です。うーん。 アーランの創作者であるジョー・アームストロングはかつて美しい言葉を言っていました。

オブジェクト指向言語の問題は、環境全体に沿ってドラッグすることです。 バナナだけが欲しかったのですが、その結果、このバナナとすべてのジャングルを保持しているゴリラが手に入ります。

バナナ、サル、ジャングルの問題を解決する


深すぎる階層を作成せずに状況から抜け出すことができます。 しかし、継承が再利用の鍵であるため、このメカニズムに制限を加えると、そこから派生する利点が明確に減ります。 そう? そうだね。 では、約束を盲目的に信じていた貧しいオブジェクト指向プログラマはどうでしょうか? 集約(含む)および委任(デリゲート)。 これについては後で詳しく説明します。

ひし形の問題


遅かれ早かれ、 この問題はitsくなり、言語によっては不溶性の頭が浮かび上がります。



ほとんどのOO言語はこれをサポートしていませんが、かなり堅牢に見えます。 どうしたの? この擬似コードを見てみましょう:

Class PoweredDevice {
}

Class Scanner inherits from PoweredDevice {
    function start() {
    }
}

Class Printer inherits from PoweredDevice {
    function start() {
    }
}

Class Copier inherits from Scanner, Printer {
}

, Scanner Printer start. start Copier? , Scanner? Printer? .


: . . - . … ? ! .

Class PoweredDevice {
}

Class Scanner inherits from PoweredDevice {
    function start() {
    }
}

Class Printer inherits from PoweredDevice {
    function start() {
    }
}

Class Copier {
    Scanner scanner
    Printer printer
    function start() {
        printer.start()
    }
}

Copier Printer Scanner. start Printer. Scanner’. — .


, . . . … . . , , … , … - … . , , . ??? … ( Java, , ):

import java.util.ArrayList;

public class Array
{
    private ArrayList<Object> a = new ArrayList<Object>();

    public void add(Object element)
    {
        a.add(element);
    }
 
    public void addAll(Object elements[])
    {
        for (int i = 0; i < elements.length; ++i)
            a.add(elements[i]); // this line is going to be changed
    }
}

: . . : add() addAll(). add() , addAll()add(). :

public class ArrayCount extends Array
{
    private int count = 0;
 
    @Override
    public void add(Object element)
    {
        super.add(element);
        ++count;
    }
 
    @Override
    public void addAll(Object elements[])
    {
        super.addAll(elements);
        count += elements.length;
    }
}

ArrayCountArray. , ArrayCount . .


. :

public void addAll(Object elements[])
{
    for (int i = 0; i < elements.length; ++i)
        add(elements[i]); //    
}

, , . . . . ArrayCount addAll() addAll(), add(), . add() , , addAll() . , .

, , . , . ! .


. « » « ». . , , . .

… . -. . , . , .


, , , . , ? , — ? , ? ?

“/” , (), — (). , (. ). , - .


“/” . ?

(Containment).

, . , “/”. . - , . , “/”, . . — . , , , ..

— . . ? , - , , . , . :


. , . , . , , . , .

,




, — - . , . , . — . !!! … , …

(The Reference Problem)


, , . , , . , , . ! ? - , , . , .


. , , , , , .. . , . , , , — . - . , .

,




— - . . , , . , , -. . - . , , . -, .




. - , -. , , . , . . , - .

?


, . . : . , . , . .

Source: https://habr.com/ru/post/J307168/


All Articles