オブジェクト指向プログラミング言語は「集合コンストラクター」をサポートしていますか?


8

いくつかのオブジェクトが互いに依存している場合があるため(たとえば、循環参照が含まれている場合)、したがって、構築後に新しいオブジェクトがいくつかの集合的制約を満たすことを確認する1つのアトミック操作の一部としてオブジェクトを作成すると便利だと最近検討しました。

これを行うには、複数のオブジェクトを作成できるコンストラクターを用意します。次に、プログラマーはすべてのコードを単一のコンストラクターに配置し、オブジェクトo 1、...、o nが作成されると、それらが必要なすべての制約を満たすようにします(たとえば、新しいオブジェクト間のすべてのリンクが既に配置されています)。私は そのような機能について聞いたことがなかったので、私は集合コンストラクターという用語を自分で作り上げましたが、この概念の受け入れられた名前がおそらく存在するかもしれません。

では、この種のコンストラクタをサポートするプログラミング言語はありますか?そうでない場合、アイデアはすでに試されていますか?


3
よくわかりませんが、最初に頭に浮かぶのはfactoryパターンです。
JensG 2014年

3
有権者は最終投票について説明できますか?非常に特殊な機能を持つプログラミング言語が存在するかどうかを尋ねています。質問はトピックから外れているようには見えないか、私には不十分に定式化されているようではありませんが、フィードバックをお待ちしています。
ジョルジオ

@JensG:私はそれについて考えましたが、工場にはいくつかの制限があります。たとえば、オブジェクトに不変の参照が含まれている場合、それをファクトリで設定することはできません。コンストラクタでのみ設定できます。ここではJavaセマンティクスを検討していますが、これは一般的な問題になる可能性があると思います。
ジョルジオ

現在、IoCコンテナーを使用してC#で同様のものをハッキングしているので、これは興味深いものです。また、これは特性を持つ言語とどのように異なり、それらの特性を混合して抽象的なメンバーを埋めることができますか?サポートされているA with Bスタイルタイプの構成に取り組んだおもちゃの言語です。その結果のコンストラクターは、基本的に2つの特性で構成される新しいタイプを作成します。
Telastyn 2014年

3
この質問は明らかに「ツール、ライブラリ、またはお気に入りのオフサイトリソースを推奨するように私たちに依頼すること」ではなく、2人が投票することでサイトを閉鎖するのは恥ずかしいことです。これをさらに明確にするために、タイトルを少し言い換えました。
Carson63000 2014年

回答:


12

これは、私にとってビルダーパターンのように聞こえます。これは、ファクトリのより複雑な形式です。Javaの例の1つはStringBuilderで、これを使用してStringを作成しbuilder.toString()、不変の結果が必要なときに呼び出します。ただし、ビルダーパターンを使用して、より複雑で均一でないオブジェクトのコレクションを構築できます。friendビルダーでセマンティクスを使用して、結果オブジェクトの作成後に不変と見なされるプライベート変数にアクセスできます。

関数型言語はインスピレーションを与えるかもしれません。たとえば、Scalaには、ビルド段階で使用できる不変のListBufferがあり、不変のListに変換されます。

関連する可能性のあるもう1つの概念はFreezable Objectsです。これにより、Freeze()メソッドが呼び出されるまでオブジェクトは変更可能と見なされます。ビルダーは、フリーズされていないオブジェクトを使用して、戻る前にそれらをフリーズできます。


フリーズ可能なオブジェクトと組み合わせたビルダーパターンのアイデアは非常に良いと思います。それは私が念頭に置いていたものとは正確には異なりますが、新しいアドホックコンセプトを導入することなく私の問題を解決します。これはIMOに適しています。
Giorgio

1:エリックリッペルトは不変オブジェクトを懸念一連の記事を持っていたし、「凍結可能」のバリエーションの一つと呼ばれるオブジェクトアイスキャンデーの不変性(:)の記事を見つけるために、便利な検索語を) -全シリーズは、複雑な不変の構築にあなたがしている場合読み取るために有用である可能性がありますC#のような言語のオブジェクト。
Alexei Levenkov、2014年

4

Ruby、Smalltalk、Self、Newspeakなどにはコンストラクタがなく、ファクトリメソッドの命名規則があります(newRubyなど)。これらは他のメソッドと同様に単なる標準のメソッドなので、必要なだけオブジェクトを割り当てて初期化するなど、必要なことを何でも実行できます。主な問題は、そのようなファクトリメソッドが、慣例により、ファクトリメソッドが呼び出されたクラスのインスタンスである単一のオブジェクトを返すことです。Foo.newつまり、呼び出すと、のインスタンスである単一のオブジェクトが返されることが期待されますFoo。しかし、十分なドキュメントがあればArray、複数の新しいオブジェクトの構造(たとえば)を返すことができます。

例:

class Foo
  def self.new
    new_foo = super

    new_bar = Bar.new
    new_bar.foo = new_foo

    new_foo.bar = new_bar

    return new_foo, new_bar
  end

  attr_accessor :bar
end

class Bar
  attr_accessor :foo
end

foo, bar = Foo.new

ECMAScriptでは、コンストラクターは単なる通常の手順です。つまり、キーワードの前にキーワードを付けるだけで、任意の手順をコンストラクターとして使用できますnew。繰り返しになりますが、これらは通常の手順であるため、必要なことは何でもできます。


1

(たとえば、循環参照が含まれている場合)[...]これを行うために、複数のオブジェクトを作成できるコンストラクターを持つことができます。次に、プログラマーは単一のコンストラクターにすべてのコードを配置して、オブジェクトo1、...、onが作成されたら、

オブジェクト間の循環依存関係?次に、答えは「コンストラクタを(ただ)使用しないでください」です。これは、循環メソッド呼び出しは意味をなさないためです。代わりに、これは一部のFactoryメソッドの古典的なシナリオです。

これは、(PHPでの)ばかげているが一般的な考え方を示す例です。Sprocket関連付けられたなしではを作成できませんWidget。各オブジェクトは、使用可能になったときに他のオブジェクトへの参照を持っています。

class Widget {            
    protected $sprocket = null;
    public function getSprocket(){ return $this->sprocket; }

    protected function __construct(){ 
        // Constructor cannot be called from outside, not public
        // Initialize self, to a limited degree
    }
    public static function create(Sprocket $partner=null){
        $me = new Widget(); // Can call constructor from same class

        // Here we can make all sorts of changes and additions and other
        // objects, wiring them all together, before revealing the result
        // to the outside world.

        if($partner !== null){
            $me->sprocket = $partner;

        }else{
            $me->sprocket = Sprocket::create($me);
        }
        return $me;
    }

}

/* 
 * Practically identical to Widget, just with some renaming
 */
class Sprocket {
    protected $widget = null;
    public function getWidget(){ return $this->widget; }

    protected function __construct(){  }
    public static function create(Widget $partner=null){            
        $me = new Sprocket();            
        if($partner !== null){
            $me->widget = $partner;
        }else{
            $me->widget = Widget::create($me);
        }
        return $me;
    }        
}

/* 
$mw = new Widget(); // NOT ALLOWED! Constructor not public
*/

$w = Widget::create(); // OK to call
$s = $w->getSprocket();
$w2 = $s->getWidget();

assert($w == $w2);

PHP 5.2でこれを実際に行う必要がある場合は、単にコンストラクターを公開したままにし、使用しないように伝えます。代わりに私はmakeWidgetWithSprocket()関数を持っているでしょう。言語がJavaの場合、パッケージレベルの可視性コントロールを使用して、間違いをさらに防ぎます。

追加の読み:

  • 多くのオプションと設定をに渡したい場合はcreate()ビルダーパターンを検討してください。
  • さまざまな方法で物事を再配線するために多くの柔軟性が必要な場合は、一般に(常にではないが)依存性注入を使用して「外部から」オブジェクトを接続するInversion of Controlフレームワークを見てください。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.