web-dev-qa-db-ja.com

クラスとデータ構造

オブジェクト指向プログラミングでは、カスタムクラス(名前のデータ、アドレスのリストなどを持つPersonクラスなど)がデータを保持し、コレクションオブジェクトを含めることもできます。データ構造は、データを保持するためにも使用されます。では、クラスは概念的に高度なデータ構造と見なされますか?そして、効率的なシステムの設計(オブジェクト指向の世界や大規模なシステム)では、クラスはデータ構造に類似していると見なされ、効率を高めるために効率的なクラスの設計のためにアルゴリズム分析が行われます(google、facebookなどの企業)?

25
Carbonizer

カスタムクラスがデータ構造であるかどうかは、誰に尋ねるかによって異なります。少なくとも、はいの人々は、それがユーザー定義のデータ構造であるよりも認めるでしょう。これは、たとえば配列、リンクリスト、バイナリツリーなどのデータ構造よりもドメイン固有で確立されていません。この答えのために、私はそれらを区別すると思います。

Big Oアルゴリズム分析をデータ構造に適用するのは簡単ですが、これらの構造の多くや他のクラスの他のインスタンスをラップするため、クラスにとっては少し複雑です...しかし、クラスインスタンスに対する多くの操作は中断される可能性がありますデータ構造の基本的な操作に至るまで、Big Oで表されます。プログラマーは、メンバーの不要なコピーを回避し、メソッドの呼び出しが多くのレイヤーを通過しないようにすることで、クラスの効率を高めることができます。そしてもちろん、メソッドでパフォーマンスの高いアルゴリズムを使用することは言うまでもありませんが、それはOOP固有ではありません。ただし、必要な場合を除いて、パフォーマンスを優先して機能、設計、および明快さを犠牲にするべきではありません。悪魔やだやだやだです。

一部の学者は、どこかで、クラスのパフォーマンスを定量化するためのメトリック、またはクラスとその操作の微積分さえも定式化しようとしたと確信していますが、まだ出会っていません。ただし、プロジェクト内のクラス間の依存関係を測定する this のようなQA調査が存在します...依存関係の数とメソッド呼び出しの階層化(したがって下位クラス)の間には相関関係があると主張する可能性がありますパフォーマンス)。しかし、誰かがこれを研究した場合、徹底的な推論を必要としない、より関連性の高いメトリックを見つけることができると確信しています。

8
Nathan Pitman

クリーンコード 第6章:オブジェクトとデータ構造を読むことをお勧めします。この章全体はこれについてです...本を購入したくない場合は要約を読むことができます、それは見つけることができます ここ

それによると、2つの異なる方法でクラスを効率的に使用できます。この現象は、データ/オブジェクトの非対称性と呼ばれます。目標に応じて、クラスが オープン/クローズド原則 に従うかどうかを決定する必要があります。
それらがOCPに従う場合、それらは多形になり、それらのインスタンスはオブジェクトとして使用されます。そのため、共通のインターフェースのデータと実装を非表示にし、そのインターフェースを実装する新しいタイプを簡単に追加できます。 MVC、IoC、すべてのラッパー、アダプターなど、ほとんどのデザインパターンがOCPを満たしています。
OCPに従わない場合、それらは多形ではなく、それらのインスタンスはデータ構造として使用されます。したがって、それらはデータを公開し、そのデータは他のクラスによって操作されます。これは、手続き型プログラミングによる典型的なアプローチでもあります。 OCPを使用しない例がいくつかあります。たとえば、DTO、例外、構成オブジェクト、 ビジターパターン などです。

OCPの実行について考え、コードをより低い抽象化レベルに移動する必要がある場合の一般的なパターン:

class Manipulator {
    doSomething(Object dataStructure){
        if (dataStructure instanceof MyType1){
            // doSomething implementation 1
        }
        else if (dataStructure instanceof MyType2)
        {
            // doSomething implementation 2
        }
        // ...
    },
    domSomethingElse(Object dataStructure){
        if (dataStructure instanceof MyType1){
            // domSomethingElse implementation 1
        }
        else if (dataStructure instanceof MyType2)
        {
            // domSomethingElse implementation 2
        }
        // ...
    }
}

class MyType1 {}
class MyType2 {}
//if you want to add a new type, every method of the Manipulator will change

修正:実装をより低い抽象化レベルに移動し、OCPを実行する

interface MyType {
    doSomething();
    domSomethingElse();
}

class MyType1 implements MyType {
    doSomething(){
        // doSomething implementation 1
    },
    domSomethingElse(){
        // domSomethingElse implementation 1
    }
}

class MyType2 implements MyType {
    doSomething(){
        // doSomething implementation 2
    },
    domSomethingElse(){
        // domSomethingElse implementation 2
    }
}

// the recently added new type
class MyType3 implements MyType {
    doSomething(){
        // doSomething implementation 3
    },
    domSomethingElse(){
        // domSomethingElse implementation 3
    }
}

OCPの違反について考え、コードをより高い抽象化レベルに移動する必要がある場合の一般的なパターン:

interface MyType {
    doSomething();
    domSomethingElse();

    //if you want to add a new method here, every class which implements this interface, will be modified
}

class MyType1 implements MyType {
    doSomething(){
        // doSomething implementation 1
    },
    domSomethingElse(){
        // domSomethingElse implementation 1
    }
}

class MyType2 implements MyType {
    doSomething(){
        // doSomething implementation 2
    },
    domSomethingElse(){
        // domSomethingElse implementation 2
    }
}

または

interface MyType {
    doSomething();
    domSomethingElse();
}

class MyType1 implements MyType {
    doSomething(){
        // doSomething implementation 1
    },
    domSomethingElse(){
        // domSomethingElse implementation 1
    }
}

class MyType2 implements MyType {
    doSomething(){
        // doSomething implementation 2
    },
    domSomethingElse(){
        // domSomethingElse implementation 2
    }
}

//adding a new type by which one or more of the methods are meaningless
class MyType3 implements MyType {
    doSomething(){
        throw new Exception("Not implemented, because it does not make any sense.");
    },
    domSomethingElse(){
        // domSomethingElse implementation 3
    }
}

修正:実装をより高い抽象化レベルに移動し、OCPに違反する

class Manipulator {
    doSomething(Object dataStructure){
        if (dataStructure instanceof MyType1){
            // doSomething implementation 1
        }
        else if (dataStructure instanceof MyType2)
        {
            // doSomething implementation 2
        }
        // ...
    },
    domSomethingElse(Object dataStructure){
        if (dataStructure instanceof MyType1){
            // domSomethingElse implementation 1
        }
        else if (dataStructure instanceof MyType2)
        {
            // domSomethingElse implementation 2
        }
        // ...
    },
    // the recently added new method
    doAnotherThing(Object dataStructure){
        if (dataStructure instanceof MyType1){
            // doAnotherThing implementation 1
        }
        else if (dataStructure instanceof MyType2)
        {
            // doAnotherThing implementation 2
        }
        // ...
    }
}

class MyType1 {}
class MyType2 {}

または、クラスをサブクラスに分割します。

同じif-elseステートメントを繰り返すだけではDRY)ではないため、通常、メソッドカウント1または2でOCPに従います。

OCPを部分的に満たし、部分的に違反する混合クラスを使用することはお勧めしません。そうすると、コードの保守が非常に困難になるためです。どのアプローチに従うかは、あらゆる状況によって決定する必要があります。これは通常簡単な決定ですが、間違えた場合でも、後でコードをリファクタリングすることができます...

24
inf3rno

概念的にクラスは[〜#〜] not [〜#〜]データ構造であり、クラスは適切に表現され、オブジェクトのクラスであり、オブジェクトは抽象(WordのC++またはC#の意味ではなく、Wordの英語の意味で)エンティティ。

クラスとオブジェクトは実践の背後にある理論のようなものであり、実践はメソッドとデータを使用したオブジェクトの実装です。データは単純な場合も複雑な場合もあります(いわゆる高度なデータ構造)。

7
Aviad P.

クラスは、単にデータとそのデータに作用できるメソッドのコレクションです。クラスを使用してデータ構造を実装できますが、それらは異なります。

リンクリストを例にとってみましょう。クラスを使用してリンクリストデータ構造を実装できます。一部の言語では、これが最もクリーンで最も明白な方法です。リンクリストを実装する方法はこれだけではありませんが、言語によっては最適な場合があります。

ただし、リンクリストはクラスであることとは何の関係もありません。リンクリストは、代わりに、各ノードが何らかの方法で次のノードにリンクされている個別のノードとしてデータを表す方法です。

データ構造は、データをモデル化する概念的な方法であり、それぞれの異なるデータ構造は、異なるプロパティとユースケースを持っています。クラスは、一部の言語がデータとメソッドをグループ化するために提供する構文上の方法です。

クラスはデータ構造を実装するために使用されるのに役立つことがよくありますが、クラス==データ構造であると言うのは誤りです。

4
Reese Moore

クラスはモデル/概念/タイプを記述し、その可能な動作と可能な状態を定義します(あなたの例では、Personは名前、アドレスなどを持つことができます。

データ構造は、何らかの方法でデータを整理およびグループ化するために使用できるタイプです。たとえば、ベクトルとリンクリストは、データを順序付けられた方法で格納するために使用できるデータ構造です。

C++のstd::vectorやJavaのJava.util.ArrayListのように、データ構造を表すクラスを持つことができます。

1
wkl