Cet article est le 20ème jour du "Calendrier de l'Avent WACUL 2016". Récemment, j'ai personnellement relu le ruby de méta-programmation et l'ai utilisé en partie au travail ~~ Il n'y a pas de nouveau matériel à parler ~~, donc cette fois je vais écrire sur le proxy dynamique.
En fait, je ne sais pas à quel point ce mot est courant ... Personnellement, "un modèle de programmation qui reçoit le nom et les paramètres d'une méthode non définie et délègue le traitement souhaité à un autre objet" Je reconnais cela.
Ceci est utile lorsque vous souhaitez écrire un wrapper pour un système externe.
Par exemple, supposons que vous souhaitiez écrire une bibliothèque cliente qui utilise une API REST externe. Par souci de simplicité, limitons-nous à GET.
GET /api/hoge
Pour exécuter, par exemple, en utilisant des requêtes en python
import requests
class Client:
def hoge(self):
return requests.get('/api/hoge')
client = Client()
client.hoge()
Etc. Rien n'est difficile. Cependant, dans ce cas, si le fuga, le piyo, etc. augmentent
class Client:
def hoge(self):
return requests.get('/api/hoge')
def fuga(self):
return requests.get('/api/fuga')
def piyo(self):
return requests.get('/api/piyo')
C'est difficile car le nombre de copies augmente.
Par conséquent, nous utilisons "une méthode spéciale qui est appelée lorsqu'une méthode ou une propriété est introuvable". Dans le cas de python,
__ getattr__`
peut être utilisé car les méthodes et les propriétés sont les mêmes et les attributs de l'objet.
class Client:
def __getattr__(self, name):
def _func(*args, **kwargs):
return requests.get('/api/' + name)
return _func
Vous pouvez maintenant prendre en charge client.hoge (), client.fuga () et client.piyo (), et le meilleur de tous, vous n'avez pas besoin de maintenir la classe Client car d'autres API seront ajoutées à l'avenir. De plus, en fonction de l'implémentation de `` _func```, vous êtes libre de gérer les paramètres que vous passez à client.method.
Tout d'abord, faisons-le en Ruby. Cette fois, j'utiliserai method_missing car je veux non seulement réduire la quantité de code mais aussi correspondre dynamiquement à des spécifications inconnues.
a.rb
class A
def method_missing(name, *args, &blk)
p name.to_s
p args
return if not block_given?
blk.call
end
end
a = A.new
a.hoge
a.fuga(1, 2, 3)
a.piyo do |i, j|
p "piyopiyo"
end
Quand vous l'exécutez, ça ressemble à ça
"hoge"
[]
"fuga"
[1, 2, 3]
"piyo"
[]
"piyopiyo"
Vient ensuite PHP. Utilisez `__ call
`. Je m'en souvenais quand j'écrivais au travail ~~ quand c'était écrit ~~. Cela fait du bien lorsqu'il est combiné avec Reflection. Pour les méthodes statiques, il existe une autre méthode appelée `` __callStatic```.
a.php
<?php
class A
{
public function __call($name, $args)
{
var_dump($name);
var_dump($args);
}
}
$a = new A();
$a->hoge();
$a->fuga("fugaarg");
Quand je le lance avec cli, ça ressemble à ça
string(4) "hoge"
array(0) {
}
string(4) "fuga"
array(1) {
[0]=>
string(7) "fugaarg"
}
Si vous l'utilisez trop, le code a tendance à être difficile à lire. Utilisez-le systématiquement.
Recommended Posts