Join MDN and developers like you at Mozilla's View Source conference, 12-14 September in Berlin, Germany. Learn more at https://viewsourceconf.org

Generic factory

XPCOM では、汎用ファクトリxpcom/glue/nsIGenericFactory.h にある機能を利用して生成されたファクトリのことを指します。

元の訳では「総称ファクトリー」となっていたが、「汎用」の方が適当ではないか

概要

ほとんどの XPCOM ファクトリは、とても単純なもので済みます。Rick Potts は、テンプレートベースの汎用ファクトリ (nsFactory<T>) を書いていますが、これによりファクトリの生成過程が単純化され、CreateInstance() メソッドを書くだけで済むようになります。新しい nsIGenericFactory インタフェースによる、もっと進んだ手段を使うことができます。これは、一つのインタフェースを、nsIFactory の簡易な実装が必要な時にいつでも再使用できるようにしたものです。そのインタフェースとその使用の記述をここに挙げます。

/**
 * 汎用的な nsIFactory の実装を提供します。この実装は、とても
 * 簡易なファクトリを必要とする DLL で使うことができます。
 */
class nsIGenericFactory : public nsIFactory {
public:
    static const nsIID& IID() { static nsIID iid = NS_IGENERICFACTORY_IID; return iid; }

    typedef NS_CALLBACK(ConstructorProcPtr) (nsISupports *aOuter, REFNSIID aIID, void **aResult);

    /**
     * 汎用ファクトリのコンストラクタ関数を設定します。
     * これは CreateInstance によって呼び出されます。
     */
    NS_IMETHOD SetConstructor(ConstructorProcPtr constructor) = 0;
};

nsIGenericFactory は、簡単に使えます。NS_GENERICFATORY_CIDのCID と NS_IGENERICFACTORY_IID の IID を使って、リポジトリから新しいインスタンスを作成します。ConstructionProcPtr プロトタイプに適合するコンストラクタ関数を定義してください。そして、その関数に対するポインタとともに nsIGenericFactory::SetConstructor を呼び出してください。それでおしまいです。これで、あなたは完全な機能を持つファクトリオブジェクトを使うことができます。

実例

class nsIComponent : public nsISupports {
public:
  NS_IMETHOD DoSomething() = 0;
};

class MyComponent : public nsIComponent {
public:
  MyComponent();
  virtual ~MyComponent();

  static NS_METHOD Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);

  NS_IMPL_ISUPPORTS

  NS_IMETHOD DoSomething();
};

このクラスのためのファクトリを作るには、単に以下のように書いてください。

nsIFactory* NewComponentFactory(nsIRepository* repository)
{
    nsIGenericFactory* factory = NULL;
    nsCID kGenericFactoryCID = NS_GENERICFACTORY_CID;
    nsresult res = repository->CreateInstance(kGenericFactoryCID, NULL, nsIGenericFactory::IID(), &factory);
    if (res == NS_OK) {
        factory->SetConstructor(&MyComponent::Create);
    }
    return factory;
}

この例では、XPCOM リポジトリは、インタフェースとして使うことができると仮定しています。(もうすぐそうなる予定です)

背景

(これは、私のオリジナルのニュース投稿 <beard-2402991733140001@h-198-93-95-151.mcom.com> が元になっています。)

我々は、異なるファクトリ実装を膨大に作ってきたと思われます。すべての単純なファクトリの代わりとして以下のクラスを使えば、コードサイズ (すべての QueryInterface、AddRef、Release の実装) を縮小できるはずです。

// アイデア: 汎用ファクトリを作ることで、多くの
 // nsIFactory コードの複製を避けられます。我々に必要なのは、
 // アロケータ関数だけです。その他の実装は、まったく同じです。
 
 #include "nsIFactory.h"
 
 class nsGenericFactory : public nsIFactory {
 public:
    typedef nsresult (*CreatorProcPtr) (nsISupports *aOuter,
                                        REFNSIID aIID, void **aResult);
 
    nsGenericFactory(CreatorProcPtr creator);
    virtual ~nsGenericFactory();
 
    NS_DECL_ISUPPORTS
 
    NS_IMETHOD CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult);
 
    NS_IMETHOD LockFactory(PRBool aLock);
 
 private:
    CreatorProcPtr mCreator;
 };
 
 nsGenericFactory::nsGenericFactory(CreatorProcPtr creator)
    :  mCreator(creator)
 {
    NS_INIT_REFCNT();
 }
 
 nsGenericFactory::~nsGenericFactory() {}
 
 static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
 
 NS_IMPL_ISUPPORTS(nsGenericFactory, kIFactoryIID)
 
 NS_IMETHODIMP nsGenericFactory::CreateInstance(nsISupports *aOuter,
                                                REFNSIID aIID, void **aResult)
 {
    return mCreator(aOuter, aIID, aResult);
 }
 
 NS_IMETHODIMP nsGenericFactory::LockFactory(PRBool aLock)
 {
    return NS_OK;
 }

多くのクラスは、クリエータ関数として使うための静的なエントリーポイントをすでに持っています。そのため、多くの場合、クラスのための新しいファクトリを作るのは、単にこんな感じでいいのです。

nsIFactory* NewMallocFactory()
{
   nsIFactory* factory = new nsGenericFactory(&nsMalloc::Create);
   factory->AddRef();
   return factory;
}

Warren に話すと、彼はこの手順を短縮するために、関数ポインタと一緒にファクトリを登録できるようにしようと提案しました。

原文書の情報

  • 著者: Patrick Beard
  • 最終更新日: February 26, 1999
  • 著作権: Portions of this content are © 1998–2007 by individual mozilla.org contributors; content available under a Creative Commons license | 詳細

ドキュメントのタグと貢献者

タグ: 
 このページの貢献者: kohei.yoshino
 最終更新者: kohei.yoshino,