Sio

Sio's Wiki Page

My "sandbag" and "progress reports" are here.

----- working -----

Lookup

What is a Lookup?

Lookupとは何ですか?

Lookup is a mechanism for finding instances of objects. It is pervasively used in NetBeans APIs. The general pattern is that you pass a Class object and get back an instance of that class or null. See the Javadoc for links to articles describing its inspiration and purpose.

Lookup はオブジェクトのインスタンスを探すための仕組みです。 NetBeans API では広範囲に使われています。一般的なパターンでは、ユーザ(プログラマ)がクラス・オブジェクトを渡し、そして、そのクラスのインスタンスか null を返します。Lookup の創造的な刺激と目的については Javadoc をご覧下さい。

The simplest way to think of Lookup is that it is a Map where the keys are Class objects and the value for each key is an instance of the key class.

Lookupについて理解する一番単純な方法は、LookupMapであると考えることです。そのMapのキーはClassオブジェクトであり、そして、各キーの値がキーのクラスのインスタンスなのです。

There is the global lookup which is used to find objects (often, but not always, singletons) that are registered throughout the system. Also, many types of objects have a method getLookup() that enables other code to get things specific to that object. In particular, Nodes and Project objects have a Lookup.

ここにシステムの至る所に登録されているオブジェクト(いつもではないけれども、しばしばそのオブジェクトはシングルトンです)を検索するのに使われる global lookup というものがあります。また、数多くの種類のオブジェクトは getLookup() というメソッドを持っており、それは他のコードがそのオブジェクト固有のものを得られるようにします。特に、複数の Node と複数の Project オブジェクトには Lookup があります。

The primary purpose of Lookup is decoupling - it makes it possible to use generic objects to get very specific information, without having to cast objects to a specific type. Confused yet? It's simple. Take the example of OpenCookie - it has one method, open() that will open a file in the editor.

Lookup の第一の目的は decoupling です。 decoupling は大変詳細な情報を得る為に、オブジェクトをある特定の型へキャストすることなしに、汎用オブジェクトを使えるようにします。まだ混乱していますか? とても簡単ですよ。 OpenCookie の例を見てみましょう。これは open() という、エディタでファイルを開くための、一個のメソッドを持っています。

Say that I want to write some code that will open the selected file when the user does something. It could be an Action, a button, or maybe my code has just created a file and I want to open it. This is what I will do:

ユーザが何かする時に、選択したファイルを開くためのいくつかのコードを私が書きたいとします。それはアクションかもしれないし、ボタンかもしれないし、あるいは、もしかしたら単にファイルを作ってそれを開きたいだけかもしれません。私がしたいことはこのようになります:

Node[] n = TopComponent.getRegistry().getActivatedNodes();
if (n.length == 1) {
   OpenCookie oc = n[0].getLookup().lookup(OpenCookie.class);
   if (oc != null) {
      oc.open();
   }
}

One can even write this code more simply, without the Nodes API at all, using Utilities.actionsGlobalContext():

このコードを ノード API 全く使わずに、 Utilities.actionsGlobalContext() を使ってもっと簡単に書く事もできます:

OpenCookie oc = Utilities.actionsGlobalContext().lookup(OpenCookie.class);
if (oc != null) {
    oc.open();
}

The power of all this is in the level of decoupling it provides: My code that wants to open the file does not have to know anything at all about what happens when the file is opened, or what kind of file it is, or what module supports opening it. And the module that supports opening it does not need to know anything about who is going to open it. They both simply share a dependency on the abstract interface OpenCookie. So either one can be replaced without affecting the other at all.

このコードの威力は、decoupling のレベルで次のような効果があります: ある特定のファイルを開こうとするコードは、そのファイルが開かれたときに何が起こったか、どのような種類のファイルなのか、どのモジュールがそれを開くことができるか等について一切知らなくてもよいのです。そして、そのファイルを開くことができるモジュールは誰がそれを開こうとしているかについて何もしる必要がありません。そのどちらも抽象化インターフェース OpenCookie の依存性を単に共有しているだけなのです。ですから、どちらか一方が他方に全く影響を与えることなく置き換えられます。

A good example of this is in the POV-Ray tutorial. It launches an external process that generates a .png file. When the process ends, it wants to open it, so it does the following:

これについての良い例は POV-Ray チュートリアル です。この例は .png ファイルを生成する外部プロセスを起動します。プロセスが終了するとき、もしファイルを開きたければ、次のようにします:

FileObject fob = FileUtil.toFileObject(new File(pathWePassedToProcess));
if (fob != null) {  //the process succeeded
   DataObject dob = DataObject.find(fob);
   OpenCookie oc = dob.getCookie(OpenCookie.class);
   if (oc != null) { //the Image module is installed
      oc.open();
   }
}

The fact is that it is the Image module that makes it possible to open .png files in NetBeans. But the POV-Ray tutorial does not need to know or care that the Image module exists, or what it does - it simply says "open this".

これで .png ファイルを NetBeans 上で開くことのできるイメージ・モジュールができました。しかし、POV-Ray チュートリアルではイメージ・モジュールが存在するかどうか、あるいはそれがなんであるかを知ったり気にしたりする必要はありません。単純に「これを開け」というだけです。

The common pattern you'll see for Lookup usage is one where there are three components:

あなたが Lookup の使い方で理解するであろう共通のパターンの1つには、3つのコンポーネントがあります。

  • Module A is pure API - it provides some interfaces
  • Module B depends on A and implements those interfaces, providing them from a Node or Project or such
  • Module C wants to display some UI or do something with objects that implement those interfaces. It also depends on A, but does not need to know about B at all; either can be replaced independently, and the other will still function.
  • モジュール A は純粋な API である - いくつかのインタフェースを提供する
  • モジュール B は A に依存し、そして B は Node や Project やそのようなものから提供されたインタフェースを実装する
  • モジュール C は いくつかの UI を表示するか、もしくは、そのようなインタフェースを実装しているオブジェクトとともに何かを行う。それもまた A に依存するが、しかし B について知る必要は全くない;両方とも自由に置き換えられるし、もう一方はそれにも関わらず機能する。

For global services, the model is more simple - typically there will be some singleton object, implemented as an abstract class:

グローバルなサービスには、そのモデルはもっと簡単です - 通常は、次のように abstract クラスで実装される、いくつかのシングルトン・オブジェクトが存在するでしょう。

public abstract class GlobalService {
   public abstract void doSomething(Something arg);
   public static GlobalService getDefault() {
     GlobalService result = Lookup.getDefault().lookup(GlobalService.class);
     if (result == null) {
        result = new NoOpGlobalService();
     }
     return result;
   }
   private static class NoOpGlobalService extends GlobalService {
      public void doSomething(Something arg) {}
   }
}

Some other module entirely actually registers an implementation of this interface in the default Lookup. StatusDisplayer is a good example of this pattern.

その他のいくつかのモジュールは、このインタフェースの実装を、完全に、そして実際に default Lookup に登録しています。 StatusDisplayer は、このパタンの良い例です。

What if multiple objects of the same type should be available?

A Lookup is not limited to containing one singleton of any type. If there may be more than one of a given type in a Lookup, the syntax is slightly different:

仮に同じ型の複数オブジェクトが利用可能な場合は?

Lookup は、どんな型の一つのシングルトンを含むかということについて制限されません。もし Lookup 内で与えられた型の一個以上のオブジェクトがあるならば、文法は若干違います。

Collection<? extends SomeIface> c = Lookup.getDefault().lookupAll(SomeIface.class);

Note: In NetBeans versions prior to 6.0 you need to use Lookup.Template as the lookupAll method is not present yet.

ノート: NetBeans のバージョンが 6.0 以前では、まだ存在しない lookupAll メソッドの代わりに、Lookup.Template を使う必要があります。

The Lookup.Result can be listened on for changes in the result of the query. It is often useful to think of a Lookup as a space in which objects appear and disappear, and your code can respond as that happens (the following code uses the NB 6.0 lookupResult method - just use the pattern above with the Lookup.Template for NetBeans 5):

Lookup.Result は問合せの結果での変更(イベント?)を待機しています。Lookup をオブジェクトが出現したり消滅したりする空間として考えることは、しばしば有用です。そしてあなたのコードは(オブジェクトの生成や消滅が)起きた事として応答できるのです。(次のコードは NB 6.0 lookupResult メソッドを使っています - NetBeans 5 では上記の Lookup.Template を使ったパタンを使ってください):

class ObjectInterestedInFooObjects implements LookupListener {
   final Lookup.Result<Foo> result;  //result object is weakly referenced inside Lookup
   ObjectInterestedInFooObjects() {
        result = someLookup.lookupResult(Foo.class);
        result.addLookupListener(this);
        resultChanged(null);
    }
    public void resultChanged(LookupEvent evt) {
        Collection<? extends Foo> c = result.allInstances();
        // do something with the result
    }
}

Another question is, on the side that's providing the lookup, if you have a collection already, how can you expose that in a Lookup. For that, you can create your own AbstractLookup and use InstanceContent to provide the collection of objects that belong in your Lookup.

lookup の話とは別に、もう一つの質問は、もしあなたがすでにコレクションを「持って」いたら、あなたはどのようにしてそれを公開するのか、ということです。そのためには、あなたは、自分の Lookup に属する自分自身の AbstractLookupInstanceContent をオブジェクトのコレクションを提供するために使うことができます。

Objects in a Lookup often are not instantiated until the first time they are requested; depending on the implementation, they may be weakly referenced, so that if an object is not used for a while, it can be garbage collected to save memory. So Lookup additionally enables lazy instantiation of objects, which is useful for performance reasons.

Lookup 内のオブジェクトは、最初に要求されるまで、しばしば実体化されません; 実装にもよりますが、それらは弱参照されているので、あるオブジェクトがしばらく使われていない場合には、メモリを空けるためにガーベージコレクションされてしまうかもしれません。ですので Lookup は付加的にオブジェクトの遅延実体化ができるようになっていて、それは性能上の理由からも便利なものです。

----- the end of working area -----

--- not touched ---

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo