web-dev-qa-db-fra.com

Besoin de bien OOP Problème de conception pour le monde et les pays

Je travaille actuellement sur un problème avec une première situation de poulet ou d'oeuf. En gros, je conçois une solution qui va comme ceci:

  • World est une collection de pays;
  • Chaque Country a un nom, un drapeau et un président (tous sont des chaînes);
  • Il y aura des relations entre les pays, comme le pays A est ami ou partisan du pays B. Il y aura donc de nombreux pays qui sont soit des amis d'autres pays, soit des pays leaders;
  • Il y aura certaines conditions pour qu'un pays soit ami ou non, en fonction du nombre de transactions entre les pays. Si le pays X exporte davantage pour dire les pays P, Q, R, S, alors X est le pays leader et P, Q, R, S sont ses amis, et ainsi de suite pour les autres pays.

À tout moment, je devrai peut-être traiter la demande comme: qui est le pays leader ultime (qui a un maximum de supporters ou d'amis, etc.), ou qui sont des supporters du pays leader ultime, ou qui sont des supporters d'un pays leader donné, etc. L'astuce ici est que les propriétés de base des amis ou des leaders sont les mêmes (comme chaque Country a un nom, un drapeau, un président)

Je veux une bonne structure squelette pour répondre aux exigences de service de base de cette déclaration de problème. Mais j'ai besoin d'un design capable de gérer toutes les extensions futures, telles que les successeurs, les descendants, la durée du pouvoir, la famille des présidents, etc.

Je suis confus en décidant quelle approche suivre: dois-je faire (approche 1) ou dois-je définir (approche 2).

Approche 1: Country fait partie de World

class World
{
    class country *country_list // not taking array , so that i need not to limit the list
};

Approche 2: Country défini en premier et World en hérite

Cela semble étrange, car Country est une petite entité et World est une grande entité. Et, alors quel serait le contenu du monde, mais encore une fois c'est une liste de pays.

class World : Inherit class country
{
    // not sure what should be the content here 
    // can getcounty();
    // add_country_to_world();
    //
};

//not sure wether to make this abstract or normal.
//no duplicates countries are allowed.

class country
{
    string countryname;
    string flag;
    string president;
};

Ensuite, je voudrais faire un mappeur qui contient une clé (faite du nom du pays) et les valeurs sont ses détails, comme le pays est un ami ou un leader, pas d'amis, afin que je puisse vérifier directement qui est le leader ultime.

18
sravs

Je n'utiliserais aucune forme d'héritage pour le monde et le pays. Le monde n'est pas un pays et un pays n'est pas le monde.

Au lieu de cela, le monde est un "sac" qui contient de nombreux pays. Par "sac", j'entends une sorte de classe de conteneur de votre choix (liste liée, ensemble, dictionnaire/carte, ou autre). Choisissez le type de conteneur qui vous permet de trouver les pays le plus efficacement.

127
Simon B

Voici une pensée ou deux:

  1. Voulez-vous vraiment modéliser le World? D'après votre description, cela ne semble pas avoir d'effet. Oui, il encapsule votre Countries, mais si c'est tout le programme, l'encapsulation des programmes devrait être correcte.
  2. Vous devez en quelque sorte modéliser les relations. Exactement comment, dépend de vos demandes, mais je pense que quelque chose comme le code ci-dessous.
  3. Envisagez un moyen de gérer les différents types de leadership. Les pays du monde sont en tête de façon très différente. Certains sont des démocraties avec un Premier ministre ou un président tandis que d'autres sont des dictatures. Si vous avez besoin d'utiliser le leadership pour quelque chose, cela doit être résolu.

classe Relations (pseudo-code simplifié)

class CountryRelation
{
    Country FirstCountry { get; set; }
    Country SecondCountry { get; set; }
    RelationshipType Relationship { get; set; }
}

enum RelationshipType {
    Friends,
    Enemies,
    Neutral
};
19
Noceo

Je pense que votre première exigence est la plus parlante:

Le monde est une collection de pays

Les autres exigences continuent de parler des pays, des dirigeants et des alliances. Il y a une chose dont je suis sûr: Sans aucun comportement, World n'est pas une classe. Au mieux, c'est une collection générique:

var world = new Collection<Country>();

Étant donné la précision des exigences pour les pays et les alliances, une collection d'objets Country pourrait même ne pas être nécessaire. Il me semble que les principales entités de ce modèle sont Country (comme vous l'avez dit) et Alliance - une relation entre deux ou plusieurs pays.

var world = new Collection<Country>();

world.Add(new Country("United States of America"));
world.Add(new Country("Portugal"));
world.Add(new Country("Saudi Arabia"));

var natoAllianceTypes = new AllianceType[] { AllianceType.Military, AllianceType.Political };
var nato = new Alliance("North Atlantic Treaty Organization", natoAllianceTypes);

nato.AddMemberNation(world.Single(c => c.Name == "United States of America"));
nato.AddMemberNation(world.Single(c => c.Name == "Portugal"));

var opecAllianceTypes = new AllianceType[] { AllianceType.Economic };
var opec = new Alliance("Organization of the Petroleum Exporting Countries", opecAllianceTypes);

opec.AddMemberNation(world.Single(c => c.Name == "Saudi Arabia"));

// so on, and so forth...

La clé ici est la classe Alliance qui colle les pays ensemble. Cela vous permet de modéliser les relations que vous désirez. Les attributs spécifiques à un pays appartiennent à la classe Country. Les attributs spécifiques à une relation entre deux ou plusieurs pays appartiennent à la classe Alliance. Déterminer qui est le pays "chef de file" semble également être une préoccupation pour la classe Alliance, ou peut-être un objet de stratégie si vous avez besoin d'abstraire ce calcul. Par exemple, l'OTAN est à la fois une alliance politique et militaire. Le leader "politique" n'est pas nécessairement le leader "militaire".

Le world? Eh bien, il n'y a pas grand chose à dire sur cet objet. C'est la source canonique de ce qui existe (mais pas nécessairement "officiellement reconnu" par la communauté internationale, qui pourrait être encore une autre alliance: Nations Unies, n'importe qui?).

12
Greg Burghardt

Le monde est-il un pays?

Votre entité la plus élémentaire est le Country. Le World est le agrégation de tous les pays (193 États membres selon le Nations Unies ). De toute évidence, World n'a ni président ni drapeau. Il ne s'agit donc pas d'un Country et ne doit pas en hériter.

Ne manque-t-il pas quelque chose à ce modèle?

Vous avez néanmoins oublié quelque chose d'important pour votre problème: les pays peuvent être agrégés pour former un Group plus grand en fonction de leurs relations. Et toutes vos questions portent essentiellement sur les propriétés de ces groupes.

enter image description here

Que World soit un Group (ou une de ses instances) est une question philosophique, et je vous laisse le soin de décider de votre modèle.

En savoir plus sur les agrégations de pays

Le Group prévoit plus qu'un Country: il a des pays membres, il peut avoir un pays leader (mais pas nécessairement), il peut être représenté par le chef de l'Etat leader ou avoir son propre représentation politique, elle peut avoir un capital formel ou informel, etc ... Nous supposons qu'il peut y avoir différents types de Group tels que les Unions, les Fédérations, les Blocs, et pas seulement les groupes de facto définis par certains rapports. Les groupes vous assureront la flexibilité parfaite pour les extensions futures et des règles plus subtiles sur la façon dont l'ensemble réagit en fonction de ses parties.

La question centrale de votre conception est de savoir si vous souhaitez utiliser Country et Groups de manière interchangeable, malgré leur différence:

  • Sinon, vous pouvez choisir composition sur héritage sans la moindre hésitation. Ce serait ma solution recommandée (voir ci-dessus).
  • Si oui, vous pouvez concevoir Country et Group sur la base de la même interface Power, en utilisant la motif composite = (voir ci-après).

enter image description here

En termes très généraux, tout votre problème concerne ensembles , sous-ensembles selon certaines règles d'appartenance et partitions . Vous pouvez facilement étendre la fonctionnalité de groupe pour les gérer tous. Et vous pourriez concevoir un gestionnaire de relations qui pourrait réviser les groupes économiques en fonction de relations nouvelles ou mises à jour.

P.S.: Tous les États de la planète n'ont pas de président. Un terme générique plus approprié serait chef d'État .

8
Christophe

Je ne veux pas devenir trop pédant si vous utilisez simplement des raccourcis, mais vous écrivez ce qui ressemble à C++:

class World
{
    class country *country_list // not taking array , so that i need not to limit the list
};

Vous voudrez certainement utiliser une structure de données ici, pas un pointeur de style C. Si rien d'autre, cela vous évite d'avoir à réimplémenter le constructeur, le destructeur et les opérations d'insertion de std::vector en C++, ArrayList en Java ou C #, std::Vec dans Rust, etc. Votre instinct était correct et ce genre de tableau dynamique et redimensionnable est ce que vous voulez normalement ici, mais vous ne devriez pas réinventer la roue.

S'il y a une opération particulièrement importante que vous effectuez particulièrement souvent, mais qui est très lente sur un tableau, comme la suppression de pays, la recherche des pays dans deux listes différentes, la fusion de deux listes sans doublons, l'insertion de pays au milieu d'une longue liste , etc., vous pouvez envisager une structure de données différente. Méfiez-vous particulièrement de tout algorithme qui prendrait du temps quadratique ou pire. (Cependant, s'il y a au plus quelques centaines de pays dans votre monde, cela importe moins.) Si le garder trié à tout moment vous permet d'optimiser, par exemple en faisant des recherches binaires au lieu de recherches exhaustives, ou en déduisant que si un pays était en la liste que vous l'auriez déjà vue, vous pouvez le faire.

3
Davislor

On dirait que vous vous concentrez trop sur la nomenclature.

World et Country sont des territoires. En fait, tout est un Territory. Les territoires contiennent des territoires, donc si j'étais vous, je le réduirais à une collection récursive de territoires et déterminerais le nombre minimum de propriétés nécessaires pour définir des territoires pour votre cas d'utilisation.

Par exemple, pour un gouvernement, vous pouvez avoir Person, Role et Responsibility comme types de base pour toutes les personnes concernées. Une personne peut jouer plusieurs rôles et les rôles peuvent avoir de nombreuses responsabilités. Avec l'héritage et les hiérarchies, vous pouvez cartographier les réseaux complexes de personnes qui forment des gouvernements et d'autres entités.

Pour les territoires, un territoire contiendrait de nombreux territoires plus petits, et chaque territoire contiendrait une collection de Relationships et vous pourriez sous-taper cela avec TradeRelationship et PoliticalRelationship etc.

Chaque personne et territoire serait une entité distincte que vous connecteriez ensuite ensemble pour former un réseau, et vous ajouteriez des propriétés et de nouveaux sous-types si nécessaire.

Le décomposer en blocs de construction les plus élémentaires est le meilleur moyen de le rendre complètement extensible à l'avenir, mais c'est aussi le moyen de le rendre très complexe, donc cela dépend de ce que vous devez réaliser à l'avenir.

Exemple en pseudo-code:

var world = new Territory {
    Name = "World",
    Children = []
};

var china = new Territory {
    Name = "People's Republic of China",
    Parents = [world],
    Children = []
};

var eu = new Union {
    Name = "European Union",
    Members = [],
    Relationships = [],
    Purposes = [UnionPurpose.Trade, UnionPurpose.Political]
};

var euChinaRelationship = new TradeRelationship {
    Participants = [eu, china]
};

eu.Relationships.Add(euChinaRelationship);
china.Relationships.Add(euChinaRelationship);

var europe = new Territory {
    Name = "Europe",
    Parents = [world],
    Children = []
};

var britain = new Territory {
    Name = "Britain",
    Parents = [europe],
    Children = []
};

var conservatives = new Union {
    Name = "Conservative Party",
    Members = [],
    Purposes = [UnionPurpose.Political]
};

var ukPrimeMinisterRole = new Role {
    Name = "Prime Minister",
    Responsibilities = ["Leading the government", "Causing trouble :P"],
    BeganAt = "24 July 2019",
    EndedAt = "12 December 2019"
};

var bojo = new Person {
    Name = "Alexander Boris de Pfeffel Johnson",
    Roles = [ukPrimeMinisterRole]
};

conservatives.Members.Add(bojo);
britain.Government = conservatives;

europe.Children.Add(britain);
eu.Members.Add(britain);

Pour un schéma de:

abstract Entity {
    Name: string;
}

Person : Entity {
    DOB: DateTime;
    DOD: DateTime;
    Roles: Role[];
    Relationships: Relationship[];
}

Role {
    Name: string;
    Responsibilities: string[];
    BeganAt: DateTime;
    EndedAt: DateTime;
}

Relationship {
    Reciprocal: boolean;
    Participants: Entity[];
}

TradeRelationship : Relationship {
    Reciprocal = true;
    override Participants: Territory[];
}

Territory : Entity {
    Parents: Territory[];
    Children: Territory[];
    Relationships: Relationship[];
    Government: Union;
}

Union : Entity {
    Members: Entity[];
    Purposes: UnionPurpose[];
    Relationships: Relationship[];
}

enum UnionPurpose {
    Political,
    Military,
    Trade
}

Cela pourrait prendre beaucoup de temps pour cartographier cela, mais le monde est assez complexe.

0
Dom

Je vois la classe "mondiale" plus comme un conteneur de pays, pas comme une base pour le pays, l'hériter pour le pays ne semble pas correct.

Pour le pays, étant donné que le nom du pays et son drapeau ne changeront guère, vous pouvez l'avoir comme une énumération.

Enum Country{
    ABC("abc", "abc_flag")


    private final String name;
    private final String flag;

    public String getName() {
        return name;
    }

    public String getFlag() {
        return flag;
    }

}

Les présidents de pays peuvent changer, et comme il existe une cartographie 1: 1, vous pouvez avoir un EnumMap simple pour cela.

EnumMap<Country, String> countryPresident.

Votre type de relation et votre mappage peuvent être une énumération comme l'a mentionné @Noceo.

enum RelationshipType {
    Friends,
    Enemies,
    Neutral
};
0
skott

Bienvenue sur Software Engineering Stackexchange!

À tout moment, je devrai peut-être traiter la demande comme: qui est le pays leader ultime (qui a un maximum de supporters ou d'amis, etc.), ou qui sont des supporters du pays leader ultime, ou qui sont des supporters d'un pays leader donné, etc. L'astuce ici est que les propriétés de base des amis ou des dirigeants sont les mêmes (comme chaque pays a un nom, un drapeau, un président)

Il me semble que la relation entre les pays est basée sur une information d'exportation. Cela me fait penser que vous pouvez le modéliser comme un graphique dirigé où chaque nœud est un pays et chaque lien du pays A vers B contient les informations sur la quantité de pays A exporté vers B. En termes de mise en œuvre, vous pouvez l'implémenter de plusieurs manières , comme une classe pour chaque pays avec deux cartes, une pour l'exportation et l'autre pour l'importation, où la clé est l'autre pays et la valeur est le montant.

Les propriétés non liées à la relation entre pays mais à un seul pays (drapeau, etc.) peuvent être de simples propriétés de cette classe.

Je veux une bonne structure squelette pour répondre aux exigences de service de base de cette déclaration de problème. Mais j'ai besoin d'un design capable de gérer toutes les extensions futures, telles que les successeurs, les descendants, la durée du pouvoir, la famille des présidents, etc.

Avoir une structure extensible est bien, mais vous ne devriez pas en faire trop. Ces exemples que vous donnez semblent être assez gros pour envisager une refactorisation s'ils deviennent nécessaires, donc je ne les considérerais pas initialement. Sur la base de mon idée précédente, un exemple d'un bon choix à l'épreuve du temps serait de représenter la relation d'export-import avec une classe au lieu d'un simple nombre, de sorte que si la nécessité d'ajouter des informations à la relation se présente, vous pouvez faire simplement.

0
bracco23