classキーワードなしで「オブジェクト指向」プログラミングを実装できますか?


29

銀行の「口座」の抽象化を提供したいとします。functionPythonでオブジェクトを使用する1つのアプローチを次に示します。

def account():
    """Return a dispatch dictionary representing a bank account.

    >>> a = account()
    >>> a['deposit'](100)
    100
    >>> a['withdraw'](90)
    10
    >>> a['withdraw'](90)
    'Insufficient funds'
    >>> a['balance']
    10
    """
    def withdraw(amount):
        if amount > dispatch['balance']:
            return 'Insufficient funds'
        dispatch['balance'] -= amount
        return dispatch['balance']
    def deposit(amount):
        dispatch['balance'] += amount
        return dispatch['balance']
    dispatch = {'balance': 0,
                'withdraw': withdraw,
                'deposit': deposit}
    return dispatch

次に、型の抽象化(classPythonのキーワード)を使用した別のアプローチを示します。

class Account(object):
    """A bank account has a balance and an account holder.

    >>> a = Account('John')
    >>> a.deposit(100)
    100
    >>> a.withdraw(90)
    10
    >>> a.withdraw(90)
    'Insufficient funds'
    >>> a.balance
    10
    """



    def __init__(self, account_holder):
        self.balance = 0
        self.holder = account_holder

    def deposit(self, amount):
        """Add amount to balance."""
        self.balance = self.balance + amount
        return self.balance

    def withdraw(self, amount):
        """Subtract amount from balance if funds are available."""
        if amount > self.balance:
            return 'Insufficient funds'
        self.balance = self.balance - amount
        return self.balance

私の先生は、classキーワードを紹介し、これらの箇条書きを見せて、トピック「オブジェクト指向プログラミング」を始めました。

オブジェクト指向プログラミング

モジュラープログラムを整理する方法:

  • 抽象化の障壁
  • メッセージパッシング
  • 情報と関連する動作をまとめる

上記の定義を満たすには、最初のアプローチで十分だと思いますか?はいの場合、なぜclassオブジェクト指向プログラミングを行うためにキーワードが必要なのですか?


2
喜んで同意します。=)私はPythonについて十分な答えを出すのに十分な知識はありませんが、JavascriptでのOOPの典型的な方法はあなたが説明する「関数オブジェクト」に似ていることを知りたいと思うかもしれません(ただし、すべてのオブジェクトに各メソッドの個別のコピーを持たせるのではなく、オブジェクトがメソッドを「共有」できるようにします;私はPython classが同様の最適化を行うと仮定します)。
Ixrec

詳細な回答が必要な場合は、別の質問をするかチャットルームに参加する必要がありますが、短い回答は(プロトタイプの継承、配列などを完全に無視する場合)基本的に正しいです。ほとんどのJSオブジェクトは、文字列キーから任意の値への辞書にすぎません。foo.bar()通常foo['bar']()、と同じであり、まれに後者の構文が実際に役立つ場合があります。
Ixrec


8
これは、OOPの基本的な理解への道のりにおいて、本当に重要な質問です。興味のある方は、私のブログ投稿を読むことができます。ここでは、言語のOOP部分に依存せずにJavaScriptで単純なオブジェクトシステムを作成しています。あなたの最初の例には重要な欠点があります:あなたが書くところobject['method'](args)、Pythonオブジェクトは実際に同等のものをしobject['method'](object, args)ます これは、基本クラスが子クラス(ストラテジーパターンなど)のメソッドを呼び出すときに関連します。
アモン

13
他の人が指摘したように、これはOOPに関する知覚的な質問です。ただし、この機会を利用して、これが実際の銀行が銀行口座を表す方法ではないことに注意してください。銀行には、借方と貸方に応じて変化する可変の「口座」オブジェクトがありません。トランザクションの書き込み専用リストがあり、トランザクションのリストから残高を計算します。良い練習として、さまざまな言語でそのメカニズムを実装してみてください。
エリック

回答:


66

おめでとうございます!オブジェクト指向は特定のプログラミング言語のサポートなしで実行できるというよく知られた事実を再発見しました。これは基本的に、この古典的な教科書の Schemeでオブジェクトが導入される方法と同じです。Schemeにはclassキーワードやそれに相当するものがなく、クラスさえも持たずにオブジェクトを作成できることに注意してください。

ただし、オブジェクト指向のパラダイムは非常に成功したため、多くの言語(およびPythonも例外ではありません)が組み込みのサポートを提供しています。これは、開発者がパラダイムを簡単に使用できるようにし、その言語のオブジェクト指向の標準形式を提供するためです。多くの言語がforループを提供するのは基本的に同じ理由ですが、whileループを1行または2行追加するだけでループをエミュレートすることもできます- 簡単に使用できます


「その言語のオブジェクト指向の標準形式を提供するために」私はそこでJavaScriptの批判を聞いていますか?;)
jpmc26

1
@ jpmc26:意図的ではありません。また、JavaScriptでオブジェクトを作成する方法については、広く受け入れられている標準があるようです。
Doc Brown

@overexchange:質問がありますか?
ドックブラウン

1
@overexchange:さて、OOPの意味は議論の余地があり、さまざまな考え方がありますが、SICPの定義は、質問の3つの箇条書きの中の1つです。絶対に抽象化を構築することですが、ポイント2と3を忘れないでください。はい、OOPコンセプトは「状態変更」を囲みますが、「不変オブジェクト」のコンセプトも許可します(JavaまたはC#の文字列クラス、Pythonいくつかの可変および不変のデータ型もあります)。質問の最初の例は、2番目の例と同様にその定義を確認します。
ドックブラウン

2
@overexchange:これは、Alain Kayのオブジェクト指向の定義(スモールトーク言語の発明者)に遡ります。このstackoverflow.com/questions/2347973/…で以前のSOの記事で包括的な答えを見つけるでしょう。私見「SICPの意味でのオブジェクト間のメッセージの受け渡し」は、オブジェクトの内部データに直接アクセスせず、「定義された通信プロトコル」を介してのみアクセスすることを意味します。Pythonのようなオブジェクト指向言語では、これは単に「オブジェクトのメソッドを呼び出す」ことを意味します。
ドックブラウン

13

私は、最初の定義があなたの先生の3つのポイントを満たすことに同意します。私たちは何のためにclassキーワードが必要だとは思いません。カバーの下で、オブジェクトとは何か、データ構造とは異なる種類のデータとデータを処理する機能を備えたものですか?もちろん、関数もデータです。

さらに進んで、オブジェクト指向プログラミングを行うことは、あなたの言語が提供するキーワードにそれほど依存していないと言います。望むなら、Cでオブジェクト指向プログラミングを行うことができます!実際、Linuxカーネルはそのような手法を採用しています。

ここでclassキーワードから推測できるのは、言語がこの種の構造をすぐにサポートすることであり、自分で機能を再実装するためにすべてのフープを通過する必要がないということです(これはかなり楽しいタスクです自体!)。あなたが得るかもしれないすべての構文上の砂糖は言うまでもありません。


継承はどうですか?サブタイプ/スーパータイプについてリアルタイムで重要ですか?私の最初のアプローチはこれを楽しまないかもしれません!!
過剰交換

5
OOPには継承は必要ありません。最初の例でも継承を実装できます。それは非常に「きれい」ではありませんが、すべて同じように可能です。
ザビエル

3
@Zaviorのコメントは、私にVB6を思い起こさせます。継承を伴わないオブジェクト指向は、実際には控えめに言っても、きれいでないコードになります。
ラバーダック

1
@overexchange考えてみると、継承とは、クラス間で共通のコード/動作を共有することです。すべてのコードを常に繰り返すことを妨げるものは何もありません。しかし、維持するのは非常にひどいでしょう。継承が存在する理由があります:)
ザビエル

1
@Zavior最も基本的な形式の「サブクラス化」は、「ここで定義している高次のディスパッチおよびデータを持つ関数を返す前に、「クラス」であるふりをする」という抽象概念です。 ha)、ThisParentFooによって参照される「スーパークラス」ディスパッチおよびデータを持つ関数をインスタンス化します。それだけです。単純な多重継承に関しては、実際にはそれですべてですが、「ダイヤモンドの問題」を導入することに注意してください。これが多重継承の問題です。
zxq9

9

もちろんできます!

セルフプログラミング言語は、すべてがオブジェクトであり、クラスまたはその他の感覚がない、動的なプロトタイプベースのオブジェクト指向言語です。オブジェクトを作成する方法のテンプレートとしてクラスを持つのではなく、プロトタイプオブジェクトのアイデアとそれらを複製するアイデアに焦点を当てています。

詳細については、http://www.selflanguage.org/を確認してください。私はそれが非常に面白いと思うし、OOPが好きなら、それほど一般的でない何かをチェックするのは良い考えだ。


0

常にではありません:言語によって異なります。Pythonでこれを行う能力を実証しましたが(Pythonタグにもかかわらず言語にとらわれないことを意図している場合)、すべての言語でこれができるわけではありません。たとえば、Javaではほとんどできません。mainを含むクラスを無視すると、classキーワードなしでmain内で定義されたオブジェクトに任意のメソッド/フィールドを定義する方法はありません。匿名クラスは存在しますが、インターフェイスが必要であり、インターフェイスで定義されているものを除き、パブリックメンバーを持つことはできません。カスタムインターフェイスを定義してからそれらの匿名クラスを作成することは可能ですが、これは事実上、クラスを使用する場合と実質的に同じですが(あまり便利ではありません)。

Doc Brownには素晴らしい答えがありますが、私がやろうとしていることは、ソリューションをまったく許可しない言語が少なくとも1つあると確信しているということです。


初心者として、「オブジェクト指向プログラミング」の概念を学ぶために、はい、言語にとらわれないようにしています。「Doc Brown」は同じ行で答えを出したと思う、彼はsicp text-chap3を読むように言ったが、これは言語構文とは何の関係もない。
過剰交換

私の答えを検証するためにクラスを使用することが絶対に必要な言語に名前を付けたいと思います。しかし、私はいくつかの言語しか知らず、悲しいかなJavaは回避策を許しています。C ++には構造体があり、Javascript flat outを使用すると、デモを行うことができます。SmalltalkとEiffelは厳密に構造化されていると聞いているため、クラスが必要になる可能性があります。
SkySpiral7

Doc Brownとして、schemeを使用してoopを学んだのであれば、この質問はしなかったでしょう。残念ながら、私が学んでいるSICPコースのバージョンはpythonを使用しています。
過剰交換

1
すべての有効なJavaプログラムにはclassキーワードが含まれている必要があるため、それほど驚くことではありません。しかし、Javaのオブジェクトシステムの上に独自のオブジェクトシステムを実装することは絶対にできますが、なぜそんなことをしたいのかはわかりません。
ブライアンゴードン

1. Javaは、この点で本当に特別です。Javaは、カスタムデータ構造の作成に使用される可能性のある他のすべてのキーワードを単純に破棄しているためです。私が知っている他のほとんどすべての言語には、レコードまたはクロージャーがあります。2. Javaでも、配列から構築されたメモリ上でプログラムできます。また、言語内で関数をクラスに配置する必要があるため、キーワードのみを使用して、その中にオブジェクト指向実装できclassます。もちろん、これは非常に理論的ですが、Javaでも組み込みクラスなしでオブジェクト指向を実行できます!
cmaster

0

あなたの先生の定義は、オブジェクト指向プログラミングの最も重要なポイントを完全に見逃しています。「メッセージの受け渡し」は、Smalltalkの人々が夢見た無意味なものであり、試行されたすべての場所で失敗に終わりました。OOPの真の力はLiskov substitutionと呼ばれるものであり、概念の説明と理解は非常に簡単ですが、基礎となる実装は非常に複雑であるため、言語レベルのサポートなしでは正しく実行できません。

Liskov置換のアイデアは、コードが特定の型の変数を予期している場所であればどこでも、その型から派生した任意の型を受け入れ、派生型の詳細を知らなくても正常に動作できることです。

たとえば、GUIフレームワークは、至る所でLiskov置換を使用します。これらは、Control「任意のコントロール」を表すことができる基本クラスを持つ傾向があります。これは、描画、サイズ変更、ユーザー入力への応答などの基本的なアクションを認識するインターフェイスを定義します。コントロールをクリックすると、UIフレームワークはClickコントロールの種類を気にせずにコントロールのメソッドを呼び出し、コントロールが独自のクラスに適切な方法でクリックを処理できるようにします。Buttonより上のクリックしたときに、制御は完全に異なる何かをしなければならないTextBox制御ほんの一例を与えるために、。

したがって、はい、上記のネストされた関数のトリックを使用してオブジェクトに似た何かを作成できますが、継承とリスコフ置換を取得できないため、真のOOPの非常に限られた代替品です。


C言語では、「struct parent {}」、次に「struct child {struct parent * ptr;}」と言えませんか?これは非oop言語構文の継承ではありませんか?
過剰交換

@overexchange:それはオブジェクト指向ではない偽の試みですが、コンパイラは一方を他方に置き換えることを許可しません。(少なくとも型キャストなしでは、引数としてaを受け取るchild*関数にa を渡すことはできませんparent*。)さらに悪いことに、C構造体にはメソッドをバインドすることができず、仮想メソッドはサポートされていません。Liskov置換の魔法を機能させるものは、手動でVMTを構築する必要がありますが、これは複雑なプロセスであり、簡単に台無しになります。
メイソンウィーラー

1
Linuxカーネルは、いくつかのオブジェクト指向技術のエミュレーションを使用します。これらはすべて、言語サポートなしで手動でコーディングする必要があります。これは多くのバグの機会につながります。これはLinuxであるため、Linusの法則の寛大な適用によって相殺されます。はい、それは可能です-同等性を証明することはこれを証明します-しかし、言語のサポートなしで正しいことをすることは非常に難しいという私のポイントはまだ立っています。また、質問がPythonに関するものであったのに、なぜこれらのCに関するすべての質問なのですか Cでは、最初から入れ子関数のトリックを行うことはできません。
メイソンウィーラー

1
@overexchange Javaはいつから「プログラマーの天国」になったのですか?
ブランディン

1
Smalltalk、Erlang、またはJavaスタイルのOOPシステムでも、メッセージの受け渡しは失敗していません。「メッセージ」とは、「関数呼び出し」とは異なるものを意味します「メソッド呼び出し」を意味する場合)。メッセージ!=関数呼び出し。本物のメッセージングは​​成功するだけでなく、大規模な並行システムと堅牢なシステムを記述するための唯一の方法であると思われます。これは、「class」キーワードなしでJavaスタイルのOOPを実装することと直交しています。それはすることができます行うこと。常に役立つとは限りません。メッセージングは​​重要です。
zxq9

-1

クイックショートアンサー

はい、プログラマは「クラス」なしでオブジェクト指向プログラミングを適用できます。

長く退屈で説明的な答え

「オブジェクト指向」にはいくつかのバリエーションがありますが、多くのプログラマーの頭に浮かぶ最初の概念は「クラス」です。

はい、プログラマは「クラス」なしでオブジェクト指向プログラミングを適用できますが、各プログラミング言語の機能と制限に制限されます。

投稿はPythonとしてタグ付けされているため、質問のタイトルは「Pythonでクラスなしのオブジェクト指向プログラミングを実装する方法」のようになります。

現在、「オブジェクトとクラス指向プログラミング」というフレーズを使用して、Javascriptの「プロトタイピング」、Visual Basic「ベース」、または「ファンクター」を使用した「Pure C」のエミュレーションなど、他のバリエーションから識別しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.