0
votes

Comment appliquer cette contrainte unique dans C #?

J'ai 2 classes: boîte et pomme.

Une boîte contient des pommes. Une pomme ne peut appartenir jamais une seule boîte. Une pomme doit appartenir à une boîte. Chaque pomme a une position dans la boîte. Cela pourrait être géré par Apple ou par boîte. Une pomme contient également un tas d'autres propriétés non pertinentes pour la boîte. Une pomme peut être déplacée d'une boîte à une autre.

Mais comment puis-je appliquer les contraintes ci-dessus?

La seule idée que j'ai est qu'une boîte conserve une trace de la position d'une pomme et d'avoir également un dictionnaire statique cartographier une pomme à une planche, mais cela semble être une bonne conception?


2 commentaires

Les classes sont comme des plans. Vous ne pouvez pas appliquer les règles à moins que vous ne les utilisiez. Mais vous n'avez pas mentionné comment essayez-vous d'utiliser les classes et de la raison pour laquelle vous devez faire respecter les règles? L'approche varie considérablement d'utilisations. Essayez de fournir plus de détails, ce que vous avez essayé jusqu'à présent, etc.


Pouvez-vous vous montrer le code pour votre solution jusqu'à présent?


5 Réponses :


2
votes

Vous pouvez créer une appelposition de classe, qui contient une pomme et une position. La boîte aura une liste d'appleposition


1 commentaires

Comment puis-je empêcher une pomme d'être ajoutée à plusieurs cases dans ce scénario?



2
votes

Je créerais une troisième classe, appelons-le Appleboxer . Cette classe serait responsable de l'ajout \ Retrait des pommes en mouvement des cases.

Appleboxer aurait une liste de tous les , lorsque vous demandez d'ajouter un Apple à n'importe quel boîte Il vérifiera si cette Apple est déjà dans une autre boîte avant d'ajouter.

Les positions gratuites \ occupées dans la case Je continuerais à la case classe.

Je pense que le principe de l'OOP ici est le Principe de responsabilité unique .

Apple n'est pas responsable de savoir dans quelle boîte il est dans.

boîte n'est pas responsable de connaître les pommes d'autres cases.


12 commentaires

Bien que cela soit la réponse correcte d'une perspective de principes de conception, il viole l'hypothèse de la question "J'ai 2 classes: boîte et pomme", qui peut faire partie des contraintes données. Pour le moment, nous ne savons pas si OP est disposé (ou peut) ajouter d'autres classes à la conception. Je supporte totalement votre solution, cependant: upvote :)


Je pense que c'est une bonne réponse, mais que se passe-t-il si quelqu'un n'utilise pas Appleboxer? Il semble que cela puisse toujours être possible d'ajouter une pomme à une autre boîte à moins que vous ne vous assuriez pas toujours d'utiliser Appleboxer, et la même instance que vous avez utilisée pour encadrer les pommes.


Vous pouvez utiliser l'inversion de dépendance (DI) et Pass Appleboxer comme paramètre sur BOX . Ensuite, sur Box.adDApple Vous utilisez l'Appleboxer fourni pour vérifier si vous pouvez ajouter la pomme. Vous pouvez faire Appleboxer un singleton pour assurer une seule instance.


Si cela est pour une API, vous pouvez également utiliser PRIVANT \ interne pour vous assurer que les développeurs ne peuvent accéder que les bonnes méthodes.


Cela semble être beaucoup de travail pour ce qui semble être un cas d'utilisation commun. Dans le monde réel, des objets n'existent que dans un endroit.


Eh bien, c'est du travail, mais le bon code paye. Je l'ai mis en place si vous souhaitez lancer un look dotnetfiddle.net/dqsgxv


Dans la solution Gabriel, ni Apple ni exposerait tout ce qui vous permettrait d'ajouter une pomme à une boîte sans utiliser de catégorie Appleboxer contenir la logique pour être sûr que chaque contrainte est remplie.


@Claudialerio Vous pouvez toujours le faire dans le même assemblage qu'il utilise interne.


Une de mes solutions dispose de 49 projets, 81 000 classes, 730.000 lignes de code ... Parlez-moi de "Beaucoup de travail" ...


"Vous pouvez toujours le faire dans la même assemblée qu'il utilise interne" : vrai, mais du point de vue de la conception est supposé que le même code de montage sait ce qu'il fait et comment utiliser des classes internes. La solution @gabrielCappelli semble toujours solide, pour moi.


En fait, même avec DI, vous pourriez toujours faire en créant une nouvelle Appleboxer vous-même et le transmettez-le au constructeur. Avec l'approche singleton, c'est la même chose que d'utiliser un champ statique comme je l'ai proposé dans la question. Et interne est bon pour les consommateurs, mais pas de bien à documenter la conception interne par une personne travaillant sur le projet.


Vous pouvez faire un singleton + laissez-passer comme un paramètre au lieu de l'avoir comme statique ... mais à ce stade était la différence? Quelqu'un travaillant sur le même projet peut TOUJOURS Casser les choses. Ils peuvent changer de code existant ou casser la conception en ajoutant des méthodes publiques qui exposent des éléments qui n'étaient pas censés être exposés, ni mille autres moyens! Le seul moyen d'empêcher les personnes ayant accès au code de briser la conception consiste à vérifier personnellement chaque commit!



1
votes

Je pense qu'un moyen simple est de créer une classe AppleboxManager contenant une liste des instances de la boîte et un dictionnaire pour mapper des pommes dans les éléments de la boîte avec des touches de substitution

La clé de substitution est une composition de BoxID + AppleID, lorsque vous ajoutez une pomme dans la boîte ajoute la clé au dictionnaire, lorsque vous modifiez la touche Apple vers une autre case, retirez la touche et ajoutez la nouvelle clé, la clé empêche la clé. duplicité. Vous devriez gérer les erreurs logiques dans Ajouter, supprimer ou modifier Apple en méthodes de boîte. Je suppose que toutes les boîtes et les pommes ont une carte d'identité unique.

Une approche similaire peut être appliquée dans la classe de la boîte avec les positions.


0 commentaires

1
votes

Le moyen le plus simple de gérer cela est de faire en sorte que la classe Apple a une référence à la case qu'elle appartient. Si vous devez obtenir toutes les pommes dans une boîte Tout ce que vous avez à faire est d'obtenir l'ID de la boîte et de rechercher toutes les pommes qui ont cet identifiant dans sa référence FK_BOXID.

Si une Apple passe à une autre boîte. Tout ce que vous avez à faire est de mettre à jour le FK_boxID dans la classe Apple pour le déplacer.

Voir exemple UML


0 commentaires

2
votes

Disclaimer: Comme indiqué par Gabriel C dans sa réponse , une conception idéale serait celle qui respecte le principe de responsabilité unique. Votre question cependant, si elle est interprétée sous licence, des contraintes à seulement 2 classes, qui devraient contenir toute la logique commerciale pour gérer la boxe des pommes. Ici, ma solution avec cette conception spécifique.

Classe Apple: strong> P>

public class Box
{
    private Apple[] _apples;

    public IEnumerable<Apple> Apples
    {
        get
        {
            return _apples.Clone() as Apple[];
        }
    }

    public Box(int maxPositions)
    {
        _apples = new Apple[maxPositions];
    }

    public void RemoveApple(Apple apple)
    {
        var position = GetApplePosition(apple);
        if (position > -1)
        {
            _apples[position] = null;
            apple.MoveToHand();
        }
    }

    public int GetApplePosition(Apple apple)
    {
        return Array.IndexOf(_apples, apple);
    }

    public void SetApplePosition(Apple apple, int position)
    {
        // if apple is already in position, do nothing
        if (object.ReferenceEquals(apple, _apples[position])) return;
        _apples[position] = apple;
    }

    public void AddApple(Apple apple, int position)
    {
        if (_apples[position] != null) throw new ArgumentException("Compartment already occupied", nameof(position));
        if (apple == null) throw new ArgumentNullException(nameof(apple));
        if (position < 0 || position > _apples.Length - 1) throw new IndexOutOfRangeException("Cannot add apple outside compartments");
        apple.MoveToBox(this, position);
    }
}


3 commentaires

Qu'est-ce que l'arrêt de quelqu'un de créer une nouvelle pomme puis de l'appeler plusieurs fois sur la même boîte ou sur différentes cases?


Vous pouvez également ajouter des cours ou les séparer tant que la contrainte d'une pomme étant liée à une boîte.


Eh bien, si les contraintes ne sont pas liées par la mise en œuvre, mais peuvent être logiques, la meilleure solution est celle proposée par Gabriel C. Selon le premier commentaire: j'ai ouvert un problème dans Repo ( GITUB.COM/CVALERIO/TOSSANAPPLETOTOREWITER/issues/1 ), je te le laisserai; GitHub Repo est public, fourche-dessus et propose une demande de tir :) (AKA: Vous ne voulez pas que nous fassions tout le travail pour vous, n'est-ce pas?)