1

Nous construisons une application iOS en utilisant Realm comme modèle/base de données, mais nous souhaitons concevoir le client afin qu'il puisse facilement prendre en charge les modifications de l'API REST-ful qui pourraient se produire dans le futur. Disons que nous développons une application pour les organisations de compétition sportive qui accueille différents événements. Chaque événement a différents types de types d'événements basés sur les sports qui sont joués. À l'heure actuelle, l'API ne renvoie que le football, le baseball et le football, mais à l'avenir, il pourrait également inclure le basketball. Plus tard, il pourrait éliminer le baseball. Je l'ai conçu les objets de royaume pour que les événements sont découplées à partir de types d'événements en utilisant un-à-plusieurs comme ceci:Comment rendre dynamique le modèle dans MVC pour iOS en fonction des modifications apportées à l'API REST-ful?

class EventTypeGroup: Object { 
    dynamic var name = "" 
    let eventTypes = List<EventType>() 
} 

class EventType: Object { 
    dynamic var name = "" 
    dynamic var descriptionText = "" 
} 

Un EventTypeGroup est la classe qui décrit les types d'événements (dans ce cas, quels sports) sera joué à l'événement. J'ai utilisé cette conception car les dictionnaires ne sont pas pris en charge dans Realm où nous pourrions stocker un type d'événement avec un ensemble de propriétés associé.

Afin de rendre le modèle adaptable aux changements futurs dans l'API au cas où des sports pour une organisation particulière sont ajoutés ou supprimés, j'ai utilisé un modèle d'usine abstrait comme ci-dessous. De cette façon, un événement ne peut pas être créé sans utiliser une énumération conforme aux principes de conception modernes de Swift. Le problème que je suis est, en supposant que nous vérifions seulement les changements de l'API pour les types d'événements (sports) une fois que l'utilisateur ouvre l'application, comment pouvons-nous changer le modèle avec l'application déjà ouverte? La base de données doit-elle être migrée si ces champs changent?

protocol EventTypeGroupFactory { 

    func createEventTypeGroup(List<EventType>) -> EventTypeGroup 

} 

protocol EventTypeFactory { 

    func createEventTypes() -> List<EventType> 

} 

class SportEventGroupFactory: EventTypeGroupFactory { 
    func createEventTypeGroup(withEventTypes: List<EventType>) -> 
    EventTypeGroup { 
     //implement logic to create an EventTypeGroup for the SportEventGroup 

    } 
} 

class SportEventTypeFactory: EventTypeFactory { 
    EventTypeGroup { 
    func createEventType() -> EventType { 
     //implement logic to create an EventType for the SportEventType 
    } 
} 


class EventTypeGroup: Object { 

    let eventTypes = List<Int> 
    enum EventType { 
    } 
} 

class EventType: Object { 

    var type: Int? 
    name: String? 
    description: String? 
} 

class Event: Object { 

    static enum EventType 
    init(eventTypeWithRawValue:) { 

    } 
} 

En outre, comment vais-je faire référence aux différentes variations des classes dans le code que je vous écris si je ne sais pas comment ils vont être définis. Je suppose que le modèle d'usine abstraite n'est peut-être pas la meilleure solution, mais je ne sais pas quelles autres options je devrais envisager ou comment aborder la question de rendre les types facilement extensibles dans un modèle basé sur les changements d'API.

Répondre

2

Vous le complimentez, je pense. Ajoutez simplement une propriété de chaîne appelée "eventType" à votre modèle d'événement.

Par exemple, normalement, si vous ne l'avez pas besoin de garder les choses dynamiques, vous pourriez faire quelque chose comme ceci:

enum EventType { 
    case soccer 
    case baseball 
    case football 
} 

// Your Event model 
struct Event { 
    var date: Date 
    var eventType: EventType // a static type :) 
} 

Mais dans votre cas, au lieu que vous pouvez faire quelque chose comme ceci:

// Your Event model without any enums 
struct Event { 
    var date: Date 
    var eventType: String // a dynamic type :(
} 

La propriété eventType peut alors être "football" ou "baseball" ou "football". (Mais le compilateur ne peut pas vous aider à attraper des erreurs maintenant.) En ce qui concerne votre stockage persistant, il suffit d'avoir un champ de type eventType et de stocker la chaîne.

Les types dynamiques me rendent triste compte tenu de la fluidité statique de Swift, mais vous obtenez ce que vous voulez. Assurez-vous de penser à des cas limites. Pour ne pas vous retrouver avec un comportement indéfini, pensez à ce que votre application est supposée faire si, par exemple, vous vous retrouvez avec des types d'événements sur le disque qui ne sont plus pris en charge par votre API REST. Par exemple, disons que vous avez un point de terminaison /eventTypes, afin que les utilisateurs de votre application puissent ajouter des événements et les classer en conséquence. Il renvoie «football», «baseball» et «football» et vos utilisateurs ont ajouté ces types d'événements et vous les avez stockés sur disque (dans Realm ou CoreData ou autre). Mais un jour, quelqu'un sur le backend (ou à travers le backend) rebaptise "football" en "football américain", et espérons que personne ne renomme "football" en "football" aussi. (Et maintenant, vous ne pouvez pas dire si une chose a été renommée ou supprimée et une autre ajoutée.) Prenez-vous alors l'union des types d'événement que vos points finaux /eventTypes et ce que vous trouvez sur le disque?Laissez-vous les utilisateurs ajouter d'anciens types d'événements qui restent sur le disque, mais qui ne sont plus pris en charge par votre API REST ou ne les affichent que?

Avec des utilisateurs actifs, vous risquez de vous retrouver avec ce type de casse si vos gens backend renommer les types d'événements ou supprimer des types d'événements (par opposition à simplement les ajouter). Discutez juste avec vos parties prenantes de ce que le comportement devrait être.

+0

Aucun dés sur la classe EventType que j'ai ajouté à votre réponse? En outre, une raison particulière vous avez choisi d'implémenter le modèle d'événement en utilisant une structure plutôt qu'une classe? – stonybrooklyn

+1

Re. structs: les structs sont plus sûrs (dans Swift, ils sont passés par valeur, pas par référence) et aussi plus rapidement à l'exécution (pas de vtable à maintenir). Mais si vous avez besoin de sous-classe et que les protocoles ne suffisent pas, alors revenez à l'utilisation des classes. – willtherussian

+1

Re. EventType class: oui, vous pouvez utiliser une classe ou une structure pour la propriété eventType si vous devez envelopper d'autres données et placer la chaîne (celle qui prendra des valeurs comme "baseball" et "football") à l'intérieur. Le fait est que vous utiliseriez toujours une chaîne au lieu d'une énumération. – willtherussian