状態、可変状態、および不変状態とは何ですか?


32

これは初心者向けの質問ですが、Googleで初心者向けの十分な答えを見つけることができませんでした。

「状態」と言うとき、人々は何を意味しますか?一般的なプログラミング、特にオブジェクト指向プログラミングでは?

また、可変および不変の状態とは何ですか-再び、一般的にプログラミングで、具体的にはOOPでも?


4
あなたの研究を共有することは皆を助けます。試したことと、それがニーズに合わなかった理由を教えてください。これは、あなたが時間をかけて自分自身を助けようとしていること、明白な答えを繰り返すことから私たちを救うこと、そして何よりもあなたがより具体的で関連性のある答えを得ることを助けることを示しています。参照してください掲載する方法
GNAT

回答:


46

値(数値、文字列、複雑なデータ構造)をIDと特定の時点に関連付けると、状態が得られます。

たとえば、数値10自体は状態を表しません。これは、明確に定義された数値であり、常に自然数10です。別の例として、文字列 "HELLO"は5文字のシーケンスです。含まれる文字とそれらが現れる順序によって完全に記述されます。500万年後、文字列「HELLO」は文字列「HELLO」のままです。純粋な値です。

状態を持つためには、これらの純粋な値がアイデンティティを持つある種のエンティティに関連付けられた世界を考えなければなりません。アイデンティティは基本的なアイデアです。つまり、2つのものが他のプロパティに関係なく区別できることを意味します。たとえば、同じモデル、同じ色の2台の車は、2台の異なる車です。

これらのものにアイデンティティが与えられている場合、純粋な値で記述されたプロパティをそれらにアタッチできます。例えば、私の車には青いという性質があります。ペアを関連付けることでこの事実を説明できます

("colour", "blue")

私の車に。ペア(「色」、「青」)は、その特定の車の状態を表す純粋な値です。

状態は、特定のエンティティだけでなく、特定の時点にも関連付けられています。だから、あなたは今日、私の車が状態を持っていると言うことができます

("colour", "blue")

明日は黒で塗り直され、新しい状態になります

("colour", "black")

エンティティの状態は変化する可能性がありますが、定義によりそのアイデンティティは変化しないことに注意してください。もちろん、エンティティが存在する限り、車は作成および破棄できますが、その生涯を通じてそのアイデンティティを保持します。まだ存在しない/もはや存在しないもののアイデンティティについて話すことは意味がありません。

特定のエンティティに関連付けられたプロパティの値が時間とともに変化する場合、そのエンティティの状態は可変であると言います。そうでなければ、状態は不変であると言います。

最も一般的な実装は、エンティティの状態をある種の変数(グローバル変数、オブジェクトメンバー変数)に保存することです。つまり、状態の現在のスナップショットを保存します。次に、割り当てを使用して可変状態が実装されます。各割り当て操作は、以前のスナップショットを新しいスナップショットに置き換えます。このソリューションでは、通常、メモリの場所を使用して現在のスナップショットを保存します。メモリ位置の上書きは、スナップショットを新しいものに置き換える破壊的な操作です。(ここでは、この場所指向のプログラミング手法に関する興味深い話を見つけることができます。)

別の方法は、エンティティの後続の状態(履歴)を値のストリーム(場合によっては無限のシーケンス)として表示することです。たとえば、SICPの第3章を参照してください。この場合、各スナップショットは異なるメモリ位置に保存され、プログラムは異なるスナップショットを同時に調べることができます。未使用のスナップショットは、不要になったときにガベージコレクションできます。

2つのアプローチの利点/欠点

  • アプローチ1は、メモリを消費せず、コピーを必要としないため、新しいスナップショットをより効率的に構築できます。
  • アプローチ1は、それへの参照を保持しているプログラムのすべての部分に暗黙的に新しい状態をプッシュします。アプローチ2は、スナップショットをオブザーバーに、たとえばイベントの形でプッシュするメカニズムが必要です。
  • アプローチ2は、一貫性のない状態エラー(部分的な状態更新など)を防ぐのに役立ちます。古い状態から新しい状態を生成する明示的な関数を定義することにより、異なる時点で生成されたスナップショットを区別しやすくなります。
  • アプローチ2は、それのような高次関数を用いて、例えば、状態自体の独立している状態でビューを容易に製造することを可能にするという点で、よりモジュール式であるmapfilter

1
状態を持つのはオブジェクトだけではないことに注意してください。プログラムが(可変)グローバル変数を使用する場合、プログラム自体は状態を持つと言われます。同様に、関数が関数呼び出し間で値を記憶する変数を持っている場合、その関数はステートフルです。
ドーバル14

2
@Doval:グローバル状態は、グローバルワールドオブジェクトの状態と考えることができます。私の知る限り、このビューはRubyなどで使用されています。状態を記憶する関数は、1つのメソッドだけでオブジェクトと同型です。一般的な基本的な考え方は、値をアイデンティティまたは場所に関連付けることです。つまり、特定のものは値を保持できますが(おそらく可変値)、アイデンティティは保持します。
ジョルジオ14

3
もちろん、私は原則的に同意します。Progは、ステートフルネスはOOP専用のものではないことを理解しているだけです。「すべてがオブジェクトである」という考え方が自然に来るとは思わない。
ドーバル14

@Doval:異なる呼び出し間で値を記憶するステートフル関数について言及しました。私が考えることができる1つの例は、Cの静的ローカル変数です。別の例は、クロージャー(コンテキストで定義された変数をキャプチャする関数)です。クロージャはオブジェクトに対してやや二重です。クロージャはメソッドが1つだけのオブジェクトであり、オブジェクトは同じ変数に対して定義されたクロージャのコレクションです。おそらくこれをすべて知っていますが、ここで要約したいと思います。一般に、指摘したように、いくつかのメモリ位置に状態を保存し、さまざまなメカニズムを使用して状態にアクセスできます。
ジョルジオ

11

状態は、単にメモリに保持されている何かに関する情報です。

オブジェクト指向の簡単な練習として、クラスをクッキーカッター、クッキーをオブジェクトと考えてください。Cookieカッター(クラス)を使用して、Cookieを作成(オブジェクトをインスタンス化)できます。Cookieのプロパティの1つがその色(食品の着色を使用して変更できる)であるとします。他のプロパティと同様に、そのCookieの色はその状態の一部です。

可変状態とは、オブジェクト(Cookie)を作成した後に変更できる状態です。不変状態は、変更できない状態です。

不変オブジェクト(状態を変更できないオブジェクト)は、同時実行、つまりコンピューター内の複数のプロセッサーがそのオブジェクトを同時に操作する能力を扱う場合に重要になります。不変性は、オブジェクトの存続期間中、状態が安定して有効であることを信頼できることを保証します。

一般に、オブジェクトの状態は「プライベート変数またはメンバー変数」に保持され、「プロパティ」またはゲッター/セッターメソッドを介してアクセスされます。


3
Progの利益のために、値が決して変化しないという事実も重要です。必要な数の関数/メソッドで使用でき、変更できないことがわかっています。可変状態では、そのオブジェクトがどのように使用されたかの履歴を追跡して、現在その値が何であるかを把握する必要があります。不変にすることでプログラムが複雑にならなければ、それは不必要な精神的なオーバーヘッドです。
ドーバル14

回答ありがとうございます。だから基本的に、OOPでは、誰かが「状態」と言うとき、それらは通常「オブジェクトのメンバー変数」を意味しますか?その場合、「可変状態」はパブリック変数、またはOOPでより一般的な、セッターメソッドを介して変更できるプライベート変数です-「不変状態」は単にプライベートメンバー変数ですか?
アビブコーン14

1
不変性は、オブジェクトのプライベートメンバーに初期値が入力された後、オブジェクトのプライベートメンバーに書き込まないことでシミュレートできます。不変性を可能な強制 setterメソッドを提供していないなど、定数を使用して、機能的なスタイルで書いて、コンストラクタのパラメータを使用して設定される初期値を必要とする:メソッドの数を使用して
ロバート・ハーヴェイの

1
状態は、あるエンティティのプロパティの値と考えています。「発送済み」は状態です。「税率」も同様です。何かの重さは状態です。現在起きているか眠っているかは状態です。何かの色は状態です。何らかの種類のコンピューターメモリに保持されている、何かに関する意味のある情報。
ロバートハーヴェイ14

1
多くの言語では、メンバー変数を「const」または「final」として宣言することにより、不変性を強制できます。このような変数は、コンストラクターによってのみ初期化できます。プライベート変数が不変であると仮定しないでください-それらはクラスの自身のメンバー関数(メソッド)によってまだ変更することができます。
サイモンB

7

「ステート」という用語(「メンバー変数」などの具体的なタイプの状態とは対照的に)は、ステートフルAPIとステートレスAPIを比較するときに最も役立つと思います。APIに言及せずに「状態」を定義しようとすることは、プログラミング言語に言及せずに「変数」または「関数」を定義しようとすることに似ています。ほとんどの正解は、単語の意味をすでに知っている人にのみ意味があります。

ステートフルvsステートレス

  • ステートフルな APIを使用すると、関数を呼び出す次回は、その情報を使用するために起こっているので、あなたはこれまでに、どのような引数で呼び出さてきたものな機能を「記憶」というものです。「記憶」の部分は多くの場合メンバー変数で実装されますが、それが唯一の方法ではありません。
  • ステートレスの APIは、すべての関数呼び出しは、単にそれに渡された引数に依存しない、と何も一つです。

たとえば、OpenGLはおそらく私が知っている最もステートフルなAPIです。少しの間、ばかげて単純化しすぎた場合、次のようになります。

glSetCurrentVertexBufferArray(vba1);
glSetCurrentVertexBufferObject(vbo1);
glSetCurrentVertexShader(vert1);
glSetCurrentFragmentShader(frag1);
// a dozen other things
glActuallyDrawStuffWithCurrentState(GL_TRIANGLES);

ほとんどすべての関数は、OpenGLが覚えておく必要のある状態を渡すために使用され、最後に、すべての描画を行うために、1つの反則的に単純な関数を呼び出します。

(簡略化された)OpenGLのステートレスバージョンは、おそらく次のようになります。

glActuallyDrawStuff(vba1, vbo1, vert1, frag1, /* a dozen other things */, GL_TRIANGLES);

状態の少ないAPIのほうが推論しやすいと人々が言うのをよく耳にします。引数の数を制御できる場合、私は一般的にそれに同意します。

可変対不変

私の知る限り、この区別は、初期状態を指定できる場合にのみ意味があります。たとえば、C ++コンストラクターの使用:

// immutable state
ImmutableWindow windowA = new ImmutableWindow(600, 400);
windowA = new ImmutableWindow(800, 600); // to change the size, I need a whole new window

// mutable state
MutableWindow windowB = new MutableWindow(600, 400);
windowB.width = 800; // to change the size, I just alter the existing object
windowB.height = 600;

ウィンドウサイズを「覚えていない」ウィンドウクラスを実装するのは困難ですが、作成後にユーザーがウィンドウサイズを変更できるかどうかを決定できます。

PS OOPでは、「状態」は通常「メンバー変数」を意味するのは事実ですが、それ以上のことがあります。たとえば、C ++では、メソッドは静的変数を持つことができ、ラムダは変数をキャプチャすることでクロージャーになることができます。どちらの場合も、これらの変数は関数への複数の呼び出しにわたって持続するため、おそらく状態と見なされます。通常の関数のローカル変数は、それらがどのように使用されるかに応じて状態と見なされる場合があります(main()にある変数はしばしばカウントされます)。


素晴らしい答え。本当にありがとうございました、あなたは本当に私がこれを速く拾うのを助けました。私はほとんど知りませんでした、私は長い間これで働いていて、それが何と呼ばれているのか知りませんでした。
the_endian 16

2

素人の言葉で

辞書の状態:

a。状況に関する状態または存在モード。

  1. 状態-その主な属性に関して何かがある方法。

何かの状態は、その属性が任意の瞬間に持っている値のセットです。

OOPでは、オブジェクトの状態は、特定の瞬間におけるその属性の値のスナップショットです。

Thing t = new Thing();
t.setColor("blue");
t.setPrice(100)
t.setSize("small");

その状態は、色が青、価格が100、サイズが小さいことです。

後で行う場合:

t.setColor("red");

その属性の1つを変更しますが、オブジェクトは以前と同じではないため、状態全体を変更しました。

クラスは、作成後にプロパティの値を変更できないように設計される場合があります。プロパティのすべての値はコンストラクターに渡されるか、データベースやファイルなどのソースから読み取られますが、「セッター」メソッドやその他の方法がないため、その瞬間にそれらの値を変更する方法はありません。オブジェクト内の値を変更します。

Thing t = new Thing("red",100,"small");
t.setColor("blue") -->> ERROR, the programmer didn't provide a setter or any other way to change the properties values after initialization.

これは、変更または変更できない状態と呼ばれます。できることは、オブジェクトを破棄し、新しいオブジェクトを作成して、同じ参照または変数に割り当てるだけです。

Thing t = new Thing("red",100,"small");
t = new Thing("blue",100,"small");
// I had to create a new Thing with another color since this thing is inmutable.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.