React Native-シングルトンを使用することはDIの最良の代替手段ですか?


8

シングルトンパターンとそれがどのように「悪い」のかについては、クラスをテストするのが難しくなるので避けてきました。シングルトンを依存性注入に置き換える方法を説明した記事をいくつか読んだことがありますが、それは不必要に複雑に思えます。

これがもう少し詳しく私の問題です。私はReact Nativeを使用してモバイルアプリを構築しています。サーバーと通信し、データを取得し、データを投稿し、ログインを処理するRESTクライアントを作成します(ログイントークンを保存し、ログイン後にリクエストごとに送信します)。

私の最初の計画は、アプリが最初にログインに使用し、必要に応じて資格情報の送信を要求するシングルトンオブジェクト(RESTClient)を作成することでした。DIのアプローチは本当に複雑に思えます(おそらくDIを使用したことがないためです)が、このプロジェクトを最大限に活用して、ここで最善を尽くしたいと思います。提案やコメントは大歓迎です。

編集:私は今、自分の質問の言葉遣いが不十分であることに気づきました。RNでシングルトンパターンを回避する方法についてのガイダンスが必要でした。幸運にも、サミュエルは私が望んでいたような答えをくれました。私の問題は、シングルトンパターンを避けてDIを使用したかったのですが、React Nativeで実装するのは本当に複雑に思えました。さらに調査を行い、Reactsコンテキストシステムを使用して実装しました。

ここに興味のある人のために、私はそれをしました。私が言ったように、私はプロップのようなものであるRNのコンテキストを使用しましたが、それはすべてのコンポーネントに伝搬されます。

ルートコンポーネントでは、次のような必要な依存関係を提供します。

export default class Root extends Component {
  getChildContext() {
    restClient: new MyRestClient();
  }

  render() {...}
}
Root.childContextTypes = {restClient: PropTypes.object};

これで、restClientは、ルートの下のすべてのコンポーネントで使用できます。このようにアクセスできます。

export default class Child extends Component {
  useRestClient() {
    this.context.restClient.getData(...);
  }

  render() {...}
}
Child.contextTypes = {restClient: PropTypes.object}

これにより、オブジェクトの作成がロジックから効果的に離れ、RESTクライアントの実装がコンポーネントから切り離されます。


3
質問のタイトルを変更することを検討してください。現在、RESTとクライアントは無関係な要素です。ここでの唯一の質問は次のとおりです。私の特定の状況では、シングルトンがDIの最良の代替手段ですか?
Laiv

反応についてはあまり知りませんが、一般的にDIは単純な概念です。もしそれが複雑だと思ったら、良い説明を読んだり聞いたりしていないのではないかと思います。
ベンアーロンソン2017

回答:


15

依存関係の注入はまったく複雑である必要はなく、学習して使用する価値があります。通常、依存関係注入フレームワークの使用により複雑になりますが、必須ではありません。

最も単純な形式では、依存性注入は、依存関係をインポートまたは構築する代わりに、依存関係を渡すことです。これは、インポートするもののパラメーターを使用するだけで実現できます。データをフェッチしてユーザーに表示MyListするために使用RESTClientする必要があるという名前のコンポーネントがあるとします。「シングルトン」アプローチは次のようになります。

import restClient from '...' // import singleton

class MyList extends React.Component {
  // use restClient and render stuff
}

これはに密結合MyListしてrestClientおり、テストMyListなしで単体テストを行うことはできませんrestClient。DIアプローチは次のようになります。

function MyListFactory(restClient) {
  class MyList extends React.Component {
    // use restClient and render stuff
  }

  return MyList
}

それだけでDIを使用できます。最大で2行のコードが追加され、インポートが不要になります。私が新しい関数「factory」を導入した理由は、AFAIKがReactで追加のコンストラクターパラメーターを渡すことができないためです。また、移植性がなく、すべての親コンポーネントがすべてを渡すことを知っている必要があるため、これらのものをReactプロパティを通じて渡しません。子供への小道具。

これでMyListコンポーネントを構築する関数ができましたが、それをどのように使用しますか?DIパターンは依存関係の連鎖を浮き彫りにします。MyAppを使用するコンポーネントがあるとしますMyList。「シングルトン」アプローチは次のようになります。

import MyList from '...'
class MyApp extends React.Component {
  render() {
    return <MyList />
  }
}

DIアプローチは次のとおりです。

function MyAppFactory(ListComponent) {
  class MyApp extends React.Component {
    render() {
      return <ListComponent />
    }
  }

  return MyApp
}

これで、直接テストMyAppせずにテストMyListできます。MyAppまったく異なる種類のリストで再利用することもできます。このパターンは、コンポジションルートまで泡立ちます。ここでファクトリを呼び出し、すべてのコンポーネントを配線します。

import RESTClient from '...'
import MyListFactory from '...'
import MyAppFactory from '...'

const restClient = new RESTClient(...)
const MyList = MyListFactory(restClient)
const MyApp = MyAppFactory(MyList)

ReactDOM.render(<MyApp />, document.getElementById('app'))

現在、システムはの単一のインスタンスを使用していますがRESTClient、コンポーネントが疎結合でテストしやすいように設計されています。


よろしければ、私の回答を参考にさせていただきたいと思います。これは、表面的に述べただけのポイントをよく表しています。
Laiv、2013

2
@Laiv、「貧しい人のDI」という言葉は時代遅れになり、「純粋なDI」を支持するようになったと思います。意図されていませんが、前者はIoCコンテナが「豊富」であることを暗示しているため、あまりにも否定的です。
David Arno

この。Dependency Injectionは初めて見たときは非常に複雑だと思いましたが、しばらくすると簡単に把握できました。そして@サミュエルはそれをうまく説明しました!
Rhys Johns

1
@Samuelでは、ReactでDIを適切に適用するには、すべてのコンポーネントのファクトリを作成する必要がありますか?また、あなたの例ではMyAppFactoryMyAppクラスを返すべきではありませんか?
Mateo Hrastnik 2017

@MattHammond依存関係のない単純なコンポーネントには、ファクトリは必要ありません。そして、これは私がやった方法であり、ReactのDIには他にも優れたアプローチがあるかもしれませんが、ここでは簡単にすることを目指していました。訂正ありがとうございます。私はそれを修正しました。
サミュエル

5

あなたの前提(学習)によると、最も単純な答えは「いいえ」です。シングルトンはDependency Injectionの最良の代替手段ではありません

学習が目標である場合、DI はシングルトンよりもツールボックスでより貴重なリソースであることがわかります。複雑に思えるかもしれませんが、学習曲線はほぼゼロから学ぶ必要があるすべてのものです。あなたの快適ゾーンの上に横たわらないでください、さもなければ、まったく学ぶことがありません。

技術的には、シングルトンシングルインスタンスの違いはほとんどありません(私があなたがやろうとしていることと思います)。DIを学ぶと、コード全体に単一のインスタンスを挿入できることがわかります。コードがテストしやすく、疎結合であることがわかります。(詳細については、サミュエルの答えをチェックしてください

しかし、ここで止まらないでください。シングルトンで同じコードを実装してください。次に、両方のアプローチを比較します。

両方の実装を理解し、これに精通することで、いつそれらが適切であるかを知ることができ、おそらく自分自身で質問に答える立場にあるでしょう。

トレーニング中、ゴールデンハンマーを作成するときです。DIの学習を避けようとすると、DIが必要になるたびにシングルトンを実装してしまう可能性があります。


0

DIとは何か、どのように使用するかを学ぶことは良い考えであるという他の回答にも同意します。

そうは言っても、シングルトンがテストを困難にしすぎるという警告は、通常、静的に型付けされた言語(C ++、C#、Javaなど)を使用している人々によって出されます。動的言語(Javascript、PHP、Python、Rubyなど)とは
対照的に、DIを使用している場合よりも、シングルトンをテスト固有の実装に置き換えることは通常ほとんど困難です。

その場合、間違いを避ける傾向があるので、あなたと共同開発者にとってより自然なデザインを使用することをお勧めします。結果がシングルトンになる場合は、それもそうです。

(しかし、もう一度:その決定を行う前にDIを学びます。)

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