L'inversion de contrôle (IoC) est une fonctionnalité importante du framework et n'est pas un terme spécial pour la programmation orientée objet. Cela n'a rien à voir avec l'injection de dépendances (DI) et la recherche de dépendances.
Les développeurs qui ont utilisé Spring devraient tous avoir une certaine compréhension de la fonction d'inversion de contrôle IOC. Lorsque vous apprenez pour la première fois, vous devriez tous savoir comment utiliser l'injection de dépendances pour implémenter les fonctions IOC. en utilisant l'inversion de contrôle IOC.
Injection de dépendances pour implémenter IOC
L'injection de dépendances est la méthode d'implémentation la plus basique d'IOC et la conception orientée objet la plus couramment utilisée. les chemins. Comment injecter des dépendances pour obtenir l'effet d'inversion de contrôle, en commençant par un exemple :
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
L'interface définit des méthodes publiques pour stocker les objets User dans une file d'attente . AbstractUserQueue则是为后续的继承类,提供了一些公用的方法实现。最后的UserFifoQueue
et UserLifoQueue,则是分别实现了FIFO 和 LIFO 队列。
C'est un moyen efficace d'obtenir un polymorphisme de sous-classe.
En créant une classe client qui dépend du type abstrait UserQueue (également appelé service dans la terminologie DI), différentes implémentations peuvent être injectées au moment de l'exécution sans avoir à refactoriser le code qui utilise la classe client :
public class UserProcessor {private UserQueue userQueue;public UserProcessor(UserQueue userQueue) {this.userQueue = userQueue; }public void process() {// process queued users here } }
UserProcessor展示了依赖注入确实是IOC的一种方式。
Nous pouvons obtenir la dépendance sur la file d'attente en l'instanciant directement dans le constructeur du UserProcessor via certaines méthodes codées en dur telles que la nouvelle opération . Mais il s’agit d’une programmation matérielle typique, qui introduit un couplage fort entre les classes client et leurs dépendances et réduit considérablement la testabilité.
Cette classe déclare sa dépendance à la classe abstraite UserQueue
dans le constructeur. C'est-à-dire que les dépendances ne sont plus exploitées en utilisant new dans le constructeur, mais sont injectées en externe, soit à l'aide d'un framework d'injection de dépendances, soit à l'aide du modèle factory ou builders.
Grâce à l'injection de dépendances, le contrôle des dépendances des classes client n'est plus localisé dans ces classes, mais se fait dans l'injecteur, voir le code suivant :
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(); }
La méthode ci-dessus a obtenu les résultats escomptés, et la UserLifoQueue的注入也简单明了。
est mise en œuvre directement via le Le mode observateur IOC est également une méthode intuitive courante. D'une manière générale, IOC est implémenté via des observateurs. Le modèle d'observateur est généralement utilisé pour suivre les changements d'état des objets du modèle dans le contexte des vues du modèle.
Dans une implémentation typique, un ou plusieurs observateurs sont liés à un objet observable (également appelé sujet dans la terminologie des modèles), par exemple en appelant la méthode addObserver. Une fois la liaison entre l'observé et l'observateur définie, les changements dans l'état de l'observé déclencheront l'opération d'appel de l'observateur. Regardez l'exemple suivant :
public interface SubjectObserver {void update(); }
Lorsque la valeur change, l'appel à l'observateur très simple mentionné ci-dessus sera déclenché. Dans des situations réelles, des API avec des fonctions plus riches sont généralement fournies, telles que la modification d'instances ou des valeurs anciennes et nouvelles qui doivent être enregistrées, mais celles-ci ne nécessitent pas d'observer le mode action (comportement), les exemples ici sont donc aussi simples que possible.
Ci-dessous, une classe d'observateur est donnée :
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()); } }
Dans la classe User, lorsque son statut est modifié via la méthode setter, elle déclenchera un appel lié à son observateur.
Utilisez des observateurs de sujet et des sujets. Les exemples suivants donnent la méthode d'observation :
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"); }
Chaque fois que l'état de l'objet User est modifié via la méthode setter, Le l'observateur sera averti et un message sera imprimé sur la console. Jusqu’à présent, un cas d’utilisation simple du modèle Observer a été présenté. Cependant, à travers ce cas d’utilisation en apparence simple, nous comprenons comment l’inversion du contrôle peut être réalisée dans cette situation.
En mode observateur, le thème joue le rôle de "couche framework", qui contrôle complètement quand et où déclencher l'appel de qui. L'initiative des observateurs est déléguée car les observateurs ne peuvent pas contrôler le moment où ils sont appelés (tant qu'ils sont inscrits sur un sujet). Cela signifie que nous pouvons réellement trouver où se produit l'inversion de contrôle - lorsque l'observateur est lié au sujet :
user.addObserver(() -> System.out.println("Observable subject " + user + " has changed its state."));
上述用例,简要说明了为什么观察者模式是实现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 框架来处理。
观察者模式:当主体发生变化时,控制从观察者传递到主体。
模板方法模式:控制发生在定义模板方法的基类中,而不是实现算法步骤的子类中。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!