it-swarm.com.de

Need Good OOP Design für Welt und Länder Problem

Ich arbeite derzeit an einem Problem mit einer ersten Situation mit Hühnchen oder Ei. Grundsätzlich entwerfe ich eine Lösung, die so aussieht:

  • World ist eine Sammlung von Ländern;
  • Jedes Country hat einen Namen, eine Flagge und einen Präsidenten (alle sind Zeichenfolgen);
  • Es wird Beziehungen zwischen Ländern geben, so wie Land A Freund oder Unterstützer von Land B ist. Es wird also viele Länder geben, die entweder Freunde anderer Länder oder der führenden Länder sind.
  • Abhängig von der Anzahl der Geschäfte zwischen den Ländern wird es einige Bedingungen geben, ob ein Land befreundet ist oder nicht. Wenn Land X mehr exportiert, um die Länder P, Q, R, S zu sagen, dann ist X das führende Land und P, Q, R, S sind seine Freunde und so weiter für andere Länder.

Zu jedem Zeitpunkt muss ich die Anfrage möglicherweise wie folgt bearbeiten: Wer ist das ultimative Führungsland (das maximale Unterstützer oder Freunde usw. hat) oder wer sind Unterstützer des ultimativen Führungslandes oder wer sind Unterstützer eines bestimmten Führungslandes? usw. Der Trick hier ist, dass die grundlegenden Eigenschaften von Freunden oder Führern gleich sind (wie jeder Country Name, Flagge, Präsident hat)

Ich möchte eine gute Skelettstruktur, um die grundlegenden Serviceanforderungen dieser Problemstellung zu erfüllen. Aber ich brauche ein Design, das in der Lage ist, zukünftige Erweiterungen wie Nachfolger, Nachkommen, Regierungsdauer, Präsidentenfamilie usw. zu bewältigen.

Ich bin verwirrt bei der Entscheidung, welchen Ansatz ich verfolgen soll: Muss ich einen Ansatz machen (Ansatz 1) oder sollte ich ihn definieren (Ansatz 2)?.

Ansatz 1: Country ist Teil von World

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

Ansatz 2: Country zuerst definiert und World erbt davon

Dies sieht seltsam aus, da Country eine kleine Entität und World eine große Entität ist. Und was wäre dann der Inhalt der Welt, aber es ist wieder eine Liste von Ländern.

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;
};

Dann möchte ich einen Mapper erstellen, der einen Schlüssel enthält (aus dem Ländernamen) und dessen Werte die Details sind, z. B. Land ist Freund oder Anführer, keine Freunde, damit ich direkt überprüfen kann, wer der ultimative Anführer ist.

18
sravs

Ich würde keine Form der Vererbung für Welt und Land verwenden. Die Welt ist kein Land, und ein Land ist nicht die Welt.

Stattdessen ist die Welt eine "Tasche", die viele Länder enthält. Mit "Tasche" meine ich eine Art Containerklasse Ihrer Wahl (verknüpfte Liste, Set, Wörterbuch/Karte oder was auch immer). Wählen Sie den Containertyp aus, mit dem Sie Länder am effizientesten finden können.

127
Simon B

Hier ist ein oder zwei Gedanken:

  1. Sind Sie sicher, dass Sie das World überhaupt modellieren müssen? Basierend auf Ihrer Beschreibung scheint es keine Wirkung zu haben. Ja, es kapselt Ihr Countries, aber wenn das alles ist, sollte die Programmkapselung in Ordnung sein.
  2. Sie müssen Beziehungen irgendwie modellieren. Wie genau, hängt von Ihren Anforderungen ab, aber ich würde so etwas wie den folgenden Code denken.
  3. Überlegen Sie, wie Sie die verschiedenen Arten von Führungsqualitäten verwalten können. Länder der Welt werden auf ganz unterschiedliche Weise geführt. Einige sind Demokratien mit einem Premierminister oder Präsidenten, während andere Diktaturen sind. Wenn Sie die Führung für etwas nutzen müssen, muss dies angesprochen werden.

Relations-Klasse (vereinfachter Pseudocode)

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

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

Ich denke, Ihre erste Anforderung ist die aussagekräftigste:

Die Welt ist eine Sammlung von Ländern

Die verbleibenden Anforderungen beziehen sich auf Länder, Führer und Allianzen. Eines bin ich mir sicher: Ohne Verhalten ist World keine Klasse. Bestenfalls handelt es sich um eine generische Sammlung:

var world = new Collection<Country>();

Angesichts der detaillierten Anforderungen an Länder und Allianzen ist möglicherweise nicht einmal eine Sammlung von Country -Objekten erforderlich. Es scheint mir, dass die Hauptentitäten in diesem Modell Country (wie Sie angegeben haben) und Alliance sind - eine Beziehung zwischen zwei oder mehr Ländern.

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...

Der Schlüssel hier ist die Alliance Klasse, die die Länder zusammenklebt. Auf diese Weise können Sie die gewünschten Beziehungen modellieren. Länderspezifische Attribute gehören zur Klasse Country. Attribute, die für eine Beziehung zwischen zwei oder mehr Ländern spezifisch sind, gehören zur Klasse Alliance. Die Bestimmung, wer das "führende" Land ist, scheint auch für die Klasse Alliance ein Problem zu sein, oder möglicherweise ein Strategieobjekt, wenn Sie diese Berechnung abstrahieren müssen. Zum Beispiel ist die NATO sowohl ein politisches als auch ein militärisches Bündnis. Der "politische" Führer muss nicht unbedingt der "militärische" Führer sein.

Das world? Zu diesem Objekt gibt es nicht viel zu sagen. Es ist die kanonische Quelle dessen, welche Länder existieren (aber nicht unbedingt "offiziell anerkannt" von der internationalen Gemeinschaft, die möglicherweise noch ein weiteres Bündnis ist: Vereinte Nationen, irgendjemand?).

12
Greg Burghardt

Ist die Welt ein Land?

Ihre grundlegendste Entität ist Country. Das World ist das Aggregation aller Länder (193 Mitgliedstaaten nach dem Vereinte Nationen ). Es ist klar, dass World keinen Präsidenten und keine Flagge hat. Es ist daher kein Country und soll nicht davon erben.

Fehlt diesem Modell nicht etwas?

Sie haben dennoch etwas Wichtiges für Ihr Problem übersehen: Länder können abhängig von ihren Beziehungen zu einem größeren Group zusammengefasst werden. Und alle Ihre Fragen beziehen sich im Wesentlichen auf die Eigenschaften dieser Gruppen.

(enter image description here

Ob World ein Group (oder eine Instanz davon) wäre, ist eine philosophische Frage, und ich überlasse es Ihnen, sich für Ihr Modell zu entscheiden.

Mehr zu Länderaggregationen

Das Group sieht mehr als ein Country vor: Es hat Mitgliedsländer, es kann ein führendes Land haben (aber nicht unbedingt), es kann durch das Oberhaupt des führenden Staates vertreten sein oder sein eigene politische Vertretung, es kann ein formelles oder informelles Kapital haben, etc ... Wir vermuten, dass es verschiedene Arten von Group wie Gewerkschaften, Verbände, Blöcke geben kann, nicht nur die von einigen definierten De-facto-Gruppen Beziehungen. Gruppen gewährleisten Ihnen die perfekte Flexibilität für zukünftige Erweiterungen und subtilere Regeln, wie das Ganze basierend auf seinen Teilen reagiert.

Die Kernfrage für Ihr Design ist, ob Sie Country und Groups trotz ihres Unterschieds austauschbar verwenden möchten:

  • Wenn nicht, können Sie Zusammensetzung statt Vererbung ohne das geringste Zögern wählen. Dies wäre meine empfohlene Lösung (siehe oben).
  • Wenn ja, können Sie Country und Group basierend auf derselben Power -Schnittstelle mit zusammengesetztes Muster entwerfen = (siehe unten).

(enter image description here

Ganz allgemein ausgedrückt geht es bei Ihrem Problem um Mengen , Teilmengen gemäß einigen Mitgliedschaftsregeln und Partitionen . Sie können die Gruppenfunktionalität problemlos erweitern, um alle zu verwalten. Und Sie könnten einen Kundenberater entwickeln, der die Wirtschaftsgruppen basierend auf neuen oder aktualisierten Beziehungen überarbeitet.

P.S.: Nicht alle Staaten auf dem Planeten haben einen Präsidenten. Ein geeigneterer Oberbegriff wäre Staatsoberhaupt .

8
Christophe

Ich möchte nicht zu pedantisch werden, wenn Sie nur Kurzschrift verwenden, aber Sie schreiben in C++:

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

Sie möchten hier definitiv eine Datenstruktur verwenden, keinen C-Zeiger. Wenn nichts anderes, erspart Ihnen dies die Mühe, die Konstruktor-, Destruktor- und Einfügeoperationen von std::vector In C++, ArrayList in Java oder C #, std::Vec In Rust usw. Ihr Instinkt war korrekt und diese Art von dynamischem, anpassbarem Array ist das, was Sie normalerweise hier wollen, aber Sie sollten das Rad nicht neu erfinden.

Wenn es eine besonders wichtige Operation gibt, die Sie besonders häufig ausführen, die jedoch in einem Array sehr langsam ist, z. B. das Löschen von Ländern, das Finden der Länder in zwei verschiedenen Listen, das Zusammenführen von zwei Listen ohne Duplikate und das Einfügen von Ländern in die Mitte einer langen Liste usw. könnten Sie eine andere Datenstruktur in Betracht ziehen. Seien Sie besonders vorsichtig bei Algorithmen, die quadratische Zeit oder schlechter benötigen. (Wenn es jedoch höchstens ein paar hundert Länder in Ihrer Welt gibt, ist dies weniger wichtig.) Wenn Sie es immer sortiert halten, können Sie optimieren, z. B. indem Sie binäre statt erschöpfende Suchvorgänge durchführen oder daraus ableiten, wenn sich ein Land in einem Land befindet Die Liste, die Sie schon gesehen hätten, können Sie tun.

3
Davislor

Es hört sich so an, als würden Sie sich zu sehr auf die Nomenklatur konzentrieren.

Sowohl World als auch Country sind Gebiete. Tatsächlich ist alles ein Territory. Gebiete enthalten Gebiete. Wenn ich Sie wäre, würde ich es auf eine rekursive Sammlung von Gebieten reduzieren und die Mindestanzahl von Eigenschaften bestimmen, die zum Definieren von Gebieten für Ihren Anwendungsfall erforderlich sind.

Für eine Regierung könnten Sie beispielsweise Person, Role und Responsibility als Basistypen für alle relevanten Personen haben. Eine Person könnte viele Rollen innehaben, und Rollen könnten viele Verantwortlichkeiten haben. Mit Vererbung und Hierarchien können Sie die komplexen Netzwerke von Menschen abbilden, die Regierungen und andere Einheiten bilden.

Für Gebiete würde ein Gebiet viele kleinere Gebiete enthalten, und jedes Gebiet würde eine Sammlung von Relationships enthalten, und Sie könnten dies mit TradeRelationship und PoliticalRelationship usw. untertippen.

Jede Person und jedes Gebiet wäre eine eigene Entität, die Sie dann zu einem Netzwerk verbinden und bei Bedarf Eigenschaften und neue Untertypen hinzufügen würden.

Die Aufteilung auf die grundlegendsten Bausteine ​​ist der beste Weg, um es in Zukunft vollständig erweiterbar zu machen. Es ist jedoch auch der Weg, es sehr komplex zu machen. Es hängt also davon ab, was Sie in Zukunft erreichen müssen.

Beispiel im Pseudocode:

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);

Für ein Schema von:

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
}

Es könnte lange dauern, dies herauszufinden, aber die Welt ist ziemlich komplex.

0
Dom

Ich sehe die 'Welt'-Klasse eher als einen Container von Ländern, nicht als eine Basis für ein Land. Es für ein Land zu erben, klingt nicht richtig.

Wenn Sie bedenken, dass sich der Ländername und die Flagge kaum ändern, können Sie für Country eine Aufzählung erstellen.

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


    private final String name;
    private final String flag;

    public String getName() {
        return name;
    }

    public String getFlag() {
        return flag;
    }

}

Die Präsidenten des Landes können sich ändern, und da es eine 1: 1-Zuordnung gibt, können Sie hierfür eine einfache EnumMap haben.

EnumMap<Country, String> countryPresident.

Ihr Beziehungstyp und Ihre Zuordnung können eine Aufzählung sein, wie @Noceo erwähnt.

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

Willkommen bei Software Engineering Stackexchange!

Zu jedem Zeitpunkt muss ich möglicherweise die Anfrage bearbeiten wie: Wer ist das ultimative Führungsland (mit maximaler Unterstützung oder Freunden usw.) oder wer sind Unterstützer des ultimativen Führungslandes oder wer sind Unterstützer eines bestimmten Führungslandes? usw. Der Trick hier ist, dass die grundlegenden Eigenschaften von Freunden oder Führern gleich sind (wie jedes Land Namen, Flagge, Präsident hat)

Es scheint mir, dass die Beziehung zwischen Ländern auf Exportinformationen basiert. Dies lässt mich denken, dass Sie es als gerichteten Graphen modellieren könnten, bei dem jeder Knoten ein Coutry ist und jede Verbindung von Land A nach B die Information darüber enthält, wie viel Land A nach B exportiert. In Bezug auf die Implementierung können Sie es auf verschiedene Arten implementieren Wie eine Klasse für jedes Land mit zwei Karten, eine für den Export und eine für den Import, wobei der Schlüssel das andere Land und der Wert der Betrag ist.

Eigenschaften, die sich nicht auf die Beziehung zwischen Ländern beziehen, sondern auf ein einzelnes Land (Flagge usw.), können einfache Eigenschaften dieser Klasse sein.

Ich möchte eine gute Skelettstruktur, um die grundlegenden Serviceanforderungen dieser Problemstellung zu erfüllen. Aber ich brauche ein Design, das in der Lage ist, zukünftige Erweiterungen wie Nachfolger, Nachkommen, Regierungsdauer, Präsidentenfamilie usw. zu bewältigen.

Eine erweiterbare Struktur ist gut, aber Sie sollten nicht zu viel tun. Diese Beispiele scheinen groß genug zu sein, um ein Refactoring in Betracht zu ziehen, falls sie jemals benötigt werden. Daher würde ich sie zunächst nicht in Betracht ziehen. Basierend auf meiner vorherigen Idee wäre ein Beispiel für eine gute zukunftssichere Wahl die Darstellung der Export-Import-Beziehung mit einer Klasse anstelle einer einfachen Zahl, sodass Sie dies tun können, wenn Sie der Beziehung Informationen hinzufügen müssen es einfach.

0
bracco23