N Inversion of Control (英語の略語) は、フレームワークの重要な機能であり、オブジェクト指向プログラミングの特別な用語ではありません。これは、依存関係の注入 (DI) および依存関係の検索 (依存関係の検索) とは何の関係もありません。
Spring を使用したことのある開発者は皆、ioc 制御関数のことを知っています。IOCを実装するための依存性注入
依存性注入はIOCの最も基本的な実装方法であり、最も一般的に使用されるオブジェクト指向設計方法の1つです。制御の反転効果を達成するために依存関係を挿入する方法、例から始めます:public interface UserQueue {void add(User user);void remove(User user); User get(); }public abstract class AbstractUserQueue implements UserQueue {protected LinkedList<User> queue = new LinkedList<>(); @Overridepublic void add(User user) { queue.addFirst(user); } @Overridepublic void remove(User user) { queue.remove(user); } @Overridepublic abstract User get(); }public class UserFifoQueue extends AbstractUserQueue {public User get() {return queue.getLast(); } }public class UserLifoQueue extends AbstractUserQueue {public User get() {return queue.getFirst(); } }
UserQueue
このインターフェイスは、User オブジェクトをキューに格納するためのパブリック メソッドを定義します。 AbstractUserQueue は、後続の継承クラスにいくつかの共通メソッド実装を提供します。最後の UserFifoQueue
と UserLifoQueue は、それぞれ FIFO キューと LIFO キューを実装します。
UserQueue
接口定义了公共的方法,用于在一个队列中去存放User对象。AbstractUserQueue则是为后续的继承类,提供了一些公用的方法实现。最后的UserFifoQueue
和 UserLifoQueue,则是分别实现了FIFO 和 LIFO 队列。
这是实现子类多态性的一种有效方式。
通过创建一个依赖于UserQueue抽象类型(也称为DI术语中的服务)的客户端类,可以在运行时注入不同的实现,无需会重构使用客户端类的代码:
public class UserProcessor {private UserQueue userQueue;public UserProcessor(UserQueue userQueue) {this.userQueue = userQueue; }public void process() {// process queued users here } }
UserProcessor展示了依赖注入确实是IOC的一种方式。
我们可以通过一些硬编码方式 如 new 操作,直接在构造函数中实例化在UserProcessor中获取对队列的依赖关系。但这是典型的代码硬编程,它引入了客户端类与其依赖关系之间的强耦合,并大大降低了可测性。
该类在构造函数中声明对抽象类 UserQueue
的依赖。也就是说,依赖关系不再通过在构造函数中使用 new 操作, 相反,通过外部注入的方式,要么使用依赖注入框架,要么使用factory或builders模式。
使用依赖注入,客户端类的依赖关系的控制,不再位于这些类中;而是在注入器中进行,看如下代码:
public static void main(String[] args) { UserFifoQueue fifoQueue = new UserFifoQueue(); fifoQueue.add(new User("user1")); fifoQueue.add(new User("user2")); fifoQueue.add(new User("user3")); UserProcessor userProcessor = new UserProcessor(fifoQueue); userProcessor.process(); }
上述方式达到了预期效果,而且对UserLifoQueue的注入也简单明了。
これは、サブクラスのポリモーフィズムを実現する効果的な方法です。
UserQueue 抽象型 (DI 用語ではサービスとも呼ばれる) に依存するクライアント クラスを作成すると、クライアント クラスを使用するコードをリファクタリングすることなく、実行時にさまざまな実装を挿入できます。 code>UserProcessor は、依存関係の注入が実際に IOC の方法であることを示しています。
UserQueue
への依存関係を宣言します。つまり、依存関係はコンストラクター内で new を使用して操作されるのではなく、依存関係注入フレームワークまたはファクトリまたはビルダー パターンを使用して外部から注入されます。 依存関係注入を使用すると、クライアント クラスの依存関係の制御はこれらのクラスに配置されなくなり、代わりにインジェクター内で行われます。次のコードを参照してください:
public interface SubjectObserver {void update(); }
UserLifoQueue の挿入も単純明快です。
オブザーバー パターンを介して IOC を直接実装することも、一般的で直感的な方法です。大まかに言うと、IOC はオブザーバーを通じて実装されます。オブザーバー パターンは通常、モデル ビューのコンテキストでモデル オブジェクトの状態変化を追跡するために使用されます。
一般的な実装では、たとえば addObserver メソッドを呼び出すことによって、1 つ以上のオブザーバーが監視可能なオブジェクト (パターン用語ではサブジェクトとも呼ばれます) にバインドされます。オブザーバーとオブザーバーの間のバインディングが定義されると、オブザーバーの状態が変化すると、オブザーバーを呼び出す操作がトリガーされます。次の例を見てください。
public class User {private String name;private List<SubjectObserver> observers = new ArrayList<>();public User(String name) {this.name = name; }public void setName(String name) {this.name = name; notifyObservers(); }public String getName() {return name; }public void addObserver(SubjectObserver observer) { observers.add(observer); }public void deleteObserver(SubjectObserver observer) { observers.remove(observer); }private void notifyObservers(){ observers.stream().forEach(observer -> observer.update()); } }
の値が変更されると、上記の非常に単純なオブザーバーへの呼び出しがトリガーされます。実際には、保存が必要なインスタンスの変更や新旧の値の変更など、より豊富な機能を備えた API が提供されることが多いですが、これらはアクション (動作) モードを監視する必要がないため、ここでは可能な限りシンプルな例を記載しています。 。
以下にオブザーバー クラスを示します。
public static void main(String[] args) { User user = new User("John"); user.addObserver(() -> System.out.println("Observable subject " + user + " has changed its state.")); user.setName("Jack"); }
user.addObserver(() -> System.out.println("Observable subject " + user + " has changed its state."));🎜🎜 User オブジェクトの状態が setter メソッドを通じて変更されるたびに、オブザーバーに通知され、メッセージがコンソールに出力されます。 。ここまでは、Observer パターンの簡単な使用例を示しました。ただし、この一見単純な使用例を通じて、この状況で制御の反転がどのように達成されるかを理解できます。 🎜🎜オブザーバーモードでは、テーマは「フレームワークレイヤー」の役割を果たし、いつ、どこで誰の呼び出しをトリガーするかを完全に制御します。オブザーバーは (トピックに登録されている限り) いつ呼び出されるかを制御できないため、オブザーバーのイニシアチブは委任されます。これは、制御の反転がどこで起こったのか、つまり観察者が主体に拘束されているとき、実際に発見できることを意味します: 🎜🎜
public abstract class EntityProcessor {public final void processEntity() { getEntityData(); createEntity(); validateEntity(); persistEntity(); }protected abstract void getEntityData();protected abstract void createEntity();protected abstract void validateEntity();protected abstract void persistEntity(); }🎜
上述用例,简要说明了为什么观察者模式是实现IoC的一种非常简单的方式。正是以这种分散式设计软件组件的形式,使得控制得以发生反转。
模板方法模式实现的思想是在一个基类中通过几个抽象方法来定义一个通用的算法,然后让子类提供具体的实现,这样保证算法结构不变。
我们可以应用这个思想,定义一个通用的算法来处理领域实体,看例子:
public abstract class EntityProcessor {public final void processEntity() { getEntityData(); createEntity(); validateEntity(); persistEntity(); }protected abstract void getEntityData();protected abstract void createEntity();protected abstract void validateEntity();protected abstract void persistEntity(); }
processEntity()
方法是个模板方法,它定义了处理实体的算法,而抽象方法代表了算法的步骤,它们必须在子类中实现。通过多次继承 EntityProcessor 并实现不同的抽象方法,可以实现若干算法版本。
虽然这说清楚了模板方法模式背后的动机,但人们可能想知道为什么这是 IOC 的模式。
典型的继承中,子类调用基类中定义的方法。而这种模式下,相对真实的情况是:子类实现的方法(算法步骤)被基类的模板方法调用。因此,控制实际是在基类中进行的,而不是在子类中。
总结:
依赖注入:从客户端获得依赖关系的控制不再存在于这些类中。它存由底层的注入器 / DI 框架来处理。
观察者模式:当主体发生变化时,控制从观察者传递到主体。
模板方法模式:控制发生在定义模板方法的基类中,而不是实现算法步骤的子类中。
以上がIOC制御反転例の詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。