Implémentation d'un système de messagerie simplifié avec Unity C# et réflexion sur le couplage

  1. Qu'est-ce que le couplage et quels sont ses inconvénients ?

Le concept de couplage, souvent comparé à des rhizomes entrelacés, décrit la dépendance entre modules logiciels. Lorsque la modification du module A provoque l'effondrement du module B, et que la modification de B impacte C, on se retrouve dans un cycle de corrections nocturnes sans fin.

Si A, B et C étaient totalement indépendants, on pourrait réparer chaque composant sans effets de bord. En isolant les fonctionnalités, on facilite la maintenance et l'évolution. L'objectif n'est pas un découplage absolu, irréaliste et source de dispersion, mais un faible couplage et une forte cohésion.

Le couplage mesure le degré d'interdépendance entre les modules d'un système logiciel. Plus les connexions sont fortes, plus le couplage est élevé et plus l'indépendance des modules est faible.

Source : https://blog.csdn.net/qq_39736982/article/details/81478176

  1. Comment réduire le couplage ?

Pour atténuer les dépendances entre deux modules, il faut diminuer leur interdépendance directe. Cependant, une dépendance totale est impossible, tout comme dans les relations humaines. La solution consiste à introduire un intermédiaire qui gère les communications, réduisant ainsi la connexion directe entre les modules.

Ce principe est similaire au pattern Médiateur : les modules n'interagissent plus directement mais via un point central, diminuant le couplage global.

  1. Système de messagerie simplifié pour le découplage

Concevons un intermédiaire, à l'image d'une plateforme de messagerie (comme WeChat), qui centralise les échanges. L'objectif est de créer :

  1. Un médiateur (plateforme)
  2. Des messages structurés (contenant un identifiant, des paramètres éventuels)

Si le médiateur reste stable, un problème dans un module n'affecte pas les autres, ce qui réduit le couplage.

3.1 Nommer les messages

Pour distinguer chaque message, on utilise un identifiant. Le type enum offre un bon compromis entre performance et lisibilité :

public enum MessageList
{
    Meet // Identifiant pour l'événement "Rencontre"
}

3.2 Définir le format des messages

Les messages transitant entre modules doivent suivre une structure fixe. On utilise des délégués génériques pour permettre des paramètres variés sans recourir à des conversions coûteuses (boxing) :

namespace xxx
{
    public delegate void Message();
    public delegate void Message<T>(T param1);
    public delegate void Message<T, P>(T param1, P param2);
    public delegate void Message<T, P, W>(T param1, P param2, W param3);
    public delegate void Message<T, P, W, G>(T param1, P param2, W param3, G param4);
}

3.3 Simuler un centre de mesasgerie (médiateur)

Le centre stocke les messages dans un dictionnaire statique :

public static class MessageCenter
{
    private static Dictionary<MessageList, Delegate> MessagePool = new Dictionary<MessageList, Delegate>();

    // Ajouter un message
    public static void Add(MessageList messageType, Message message)
    {
        if (MessagePool.ContainsKey(messageType))
        {
            MessagePool[messageType] = (Message)MessagePool[messageType] + message;
        }
        else
        {
            MessagePool.Add(messageType, message);
        }
    }

    // Vérifier l'existence et la non-nullité
    private static bool IsInDic(MessageList messageType)
    {
        return MessagePool.ContainsKey(messageType) && MessagePool[messageType] != null;
    }

    // Exécuter un message
    public static void Invoke(MessageList eventType)
    {
        if (IsInDic(eventType))
        {
            Message msg = MessagePool[eventType] as Message;
            msg?.Invoke();
        }
    }

    // Supprimer un message
    public static void Remove(MessageList messageType, Message message)
    {
        if (MessagePool.ContainsKey(messageType))
        {
            MessagePool[messageType] = (Message)MessagePool[messageType] - message;
            if (MessagePool[messageType] == null)
            {
                MessagePool.Remove(messageType);
            }
        }
    }
}

Trois opérations fondamentales : Ajout, Suppression, Exécution.

3.4 Utilisation

void Achievement()
{
    MessageCenter.Add(MessageList.Meet, AllerParcAvecPartenaire1);
    MessageCenter.Add(MessageList.Meet, AllerParcAvecPartenaire2);
    MessageCenter.Remove(MessageList.Meet, AllerParcAvecPartenaire2);
    MessageCenter.Invoke(MessageList.Meet);
}

void AllerParcAvecPartenaire1()
{
    Debug.Log("Partenaire 1 se rend au parc.");
}

void AllerParcAvecPartenaire2()
{
    Debug.Log("Partenaire 2 se rend au parc.");
}

Ce mécanisme devient crucial lorsque les méthodes appartiennent à des structures complexes distinctes, où un appel direct entraînerait un couplage fort. Le pattern Médiateur permet de découpler les modules en les liant uniquement au centre de messagerie.

Étiquettes: Unity C# couplage médiateur mécanisme de messagerie

Publié le 20 juillet à 13h26