Je voudrais créer une fonction abstraite dans un langage rapide. C'est possible?
class BaseClass {
func abstractFunction() {
// How do I force this function to be overridden?
}
}
class SubClass : BaseClass {
override func abstractFunction() {
// Override
}
}
Réponses:
Il n'y a pas de concept d'abstrait dans Swift (comme Objective-C) mais vous pouvez le faire:
la source
assert(false, "This method must be overriden by the subclass")
.fatalError("This method must be overridden")
preconditionFailure("Bla bla bla")
dans Swift qui s'exécutera dans les versions de version et élimine également le besoin d'une déclaration de retour. EDIT: Juste a découvert que cette méthode est essentiellement égale à ,fatalError()
mais c'est la façon plus appropriée (documentation mieux, a présenté à Swift avecprecondition()
,assert()
etassertionFailure()
, lire ici )Ce que vous voulez, ce n'est pas une classe de base, mais un protocole.
Si vous ne fournissez pas abstractFunction dans votre classe, c'est une erreur.
Si vous avez toujours besoin de la classe de base pour un autre comportement, vous pouvez le faire:
la source
Je porte une bonne quantité de code depuis une plate-forme qui prend en charge les classes de base abstraites vers Swift et j'y suis souvent connecté. Si ce que vous voulez vraiment, c'est la fonctionnalité d'une classe de base abstraite, cela signifie que cette classe sert à la fois d'implémentation de fonctionnalité de classe partagée (sinon ce serait juste une interface / protocole) ET qu'elle définit des méthodes qui doivent être implémentées par classes dérivées.
Pour ce faire dans Swift, vous aurez besoin d'un protocole et d'une classe de base.
Notez que la classe de base implémente la ou les méthodes partagées, mais n'implémente pas le protocole (car elle n'implémente pas toutes les méthodes).
Puis dans la classe dérivée:
La classe dérivée hérite de sharedFunction de la classe de base, ce qui l'aide à satisfaire cette partie du protocole, et le protocole nécessite toujours que la classe dérivée implémente abstractFunction.
Le seul inconvénient réel de cette méthode est que, puisque la classe de base n'implémente pas le protocole, si vous avez une méthode de classe de base qui a besoin d'accéder à une propriété / méthode de protocole, vous devrez la remplacer dans la classe dérivée, et à partir de là, appeler la classe de base (via super) passant de
self
sorte que la classe de base ait une instance du protocole avec laquelle faire son travail.Par exemple, disons que sharedFunction avait besoin d'appeler abstractFunction. Le protocole resterait le même et les classes ressembleraient maintenant à:
Maintenant, la fonction sharedFunction de la classe dérivée satisfait cette partie du protocole, mais la classe dérivée est toujours capable de partager la logique de la classe de base d'une manière raisonnablement simple.
la source
Celui-ci semble être la manière "officielle" dont Apple gère les méthodes abstraites dans UIKit. Jetez un œil à
1. Mettez la méthode abstraite dans un protocole 2. Écrivez votre classe de base 3. Écrivez la ou les sous-classes. Voici comment utiliser tout celaUITableViewController
la façon dont il fonctionneUITableViewDelegate
. L' une des premières choses que vous faites, est d'ajouter une ligne:delegate = self
. Eh bien, c'est exactement le truc.Vérifiez avec Playground pour voir la sortie.
Quelques remarques
UITableViewController
implémenteUITableViewDelegate
mais doit toujours être des registres en tant que délégué en définissant explicitement ladelegate
propriété.la source
getComments
méthode sur le délégué parent. Il existe une poignée de types de commentaires, et je veux ceux qui sont pertinents pour chaque objet. Donc, je veux que les sous-classes ne se compilent pas quand je le faisdelegate.getComments()
si je ne remplace pas cette méthode. Le VC sait simplement qu'il a unParentDelegate
objet appelédelegate
, ouBaseClassX
dans votre exemple, maisBaseClassX
n'a pas la méthode abstraite. J'aurais besoin que le VC sache spécifiquement qu'il utilise leSubclassedDelegate
.Une façon de faire est d'utiliser une fermeture facultative définie dans la classe de base, et les enfants peuvent choisir de l'implémenter ou non.
la source
Eh bien, je sais que je suis en retard au match et que je profite peut-être des changements qui se sont produits. Désolé pour ça.
Dans tous les cas, j'aimerais apporter ma réponse, car j'aime faire des tests et les solutions avec
fatalError()
est, AFAIK, non testable et celles avec des exceptions sont beaucoup plus difficiles à tester.Je suggérerais d'utiliser une approche plus rapide . Votre objectif est de définir une abstraction qui a des détails communs, mais qui ne sont pas entièrement définis, c'est-à-dire la ou les méthodes abstraites. Utilisez un protocole qui définit toutes les méthodes attendues dans l'abstraction, à la fois celles qui sont définies et celles qui ne le sont pas. Créez ensuite une extension de protocole qui implémente les méthodes définies dans votre cas. Enfin, toute classe dérivée doit implémenter le protocole, ce qui signifie toutes les méthodes, mais celles qui font partie de l'extension de protocole ont déjà leur implémentation.
Prolonger votre exemple avec une fonction concrète:
Notez qu'en faisant cela, le compilateur est à nouveau votre ami. Si la méthode n'est pas "surchargée", vous obtiendrez une erreur au moment de la compilation, au lieu de celles que vous obtiendriez avec
fatalError()
ou des exceptions qui se produiraient au moment de l'exécution.la source
Je comprends ce que tu fais maintenant, je pense que tu ferais mieux d'utiliser un protocole
Ensuite, vous vous conformez simplement au protocole:
Si votre classe est également une sous-classe, les protocoles suivent la superclasse:
la source
Utilisation de
assert
mots-clés pour appliquer des méthodes abstraites:Cependant, comme Steve Waddicor l'a mentionné, vous en voulez probablement un à la
protocol
place.la source
Je comprends la question et je cherchais la même solution. Les protocoles ne sont pas les mêmes que les méthodes abstraites.
Dans un protocole, vous devez spécifier que votre classe est conforme à ce protocole, une méthode abstraite signifie que vous devez remplacer cette méthode.
En d'autres termes, les protocoles sont des sortes d'options, vous devez spécifier la classe de base et le protocole, si vous ne spécifiez pas le protocole, vous n'avez pas à remplacer ces méthodes.
Une méthode abstraite signifie que vous voulez une classe de base mais que vous devez implémenter votre propre méthode ou deux, ce qui n'est pas la même chose.
J'ai besoin du même comportement, c'est pourquoi je cherchais une solution. Je suppose que Swift manque une telle fonctionnalité.
la source
Il existe une autre alternative à ce problème, bien qu'il y ait toujours un inconvénient par rapport à la proposition de @ jaumard; il nécessite une déclaration de retour. Bien que je manque le point de l'exiger, car cela consiste à lancer directement une exception:
Puis:
Tout ce qui vient après est inaccessible, donc je ne vois pas pourquoi forcer le retour.
la source
AbstractMethodException().raise()
?Je ne sais pas si cela va être utile, mais j'ai eu un problème similaire avec la méthode abstraite en essayant de créer le jeu SpritKit. Ce que je voulais, c'est une classe animale abstraite qui a des méthodes telles que move (), run () etc., mais les noms de sprite (et d'autres fonctionnalités) devraient être fournis par les enfants de la classe. J'ai donc fini par faire quelque chose comme ça (testé pour Swift 2):
la source