Dieser Artikel ist der 20. Tag des "WACUL Adventskalenders 2016". Kürzlich habe ich den Meta-Programmier-Rubin persönlich zurückgelesen und ihn teilweise bei der Arbeit verwendet ~~ Es gibt kein neues Material, über das ich sprechen könnte ~~, also werde ich dieses Mal über dynamischen Proxy schreiben.
Eigentlich bin ich mir nicht sicher, wie häufig dieses Wort vorkommt ... Persönlich "ein Programmiermuster, das den Namen und die Parameter einer undefinierten Methode empfängt und die gewünschte Verarbeitung an ein anderes Objekt delegiert" Ich erkenne das.
Dies ist nützlich, wenn Sie einen Wrapper für ein externes System schreiben möchten.
Angenommen, Sie möchten eine Clientbibliothek schreiben, die eine externe REST-API verwendet. Der Einfachheit halber beschränken wir uns auf GET.
GET /api/hoge
So führen Sie beispielsweise Anforderungen in Python aus
import requests
class Client:
def hoge(self):
return requests.get('/api/hoge')
client = Client()
client.hoge()
Und so weiter. Nichts ist schwierig. In diesem Fall jedoch, wenn Fuga, Piyo usw. zunehmen
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')
Es ist schwierig, weil die Anzahl der Kopien zunimmt.
Daher verwenden wir "eine spezielle Methode, die aufgerufen wird, wenn eine Methode oder Eigenschaft nicht gefunden werden kann". Im Fall von Python kann `__ getattr__
`verwendet werden, da die Methoden und Eigenschaften und die Attribute des Objekts identisch sind.
class Client:
def __getattr__(self, name):
def _func(*args, **kwargs):
return requests.get('/api/' + name)
return _func
Jetzt können Sie client.hoge (), client.fuga () und client.piyo () unterstützen, und das Beste ist, dass Sie die Client-Klasse nicht mehr pflegen müssen, da in Zukunft weitere APIs hinzugefügt werden. Abhängig von der Implementierung von `` _func``` können Sie auch die Parameter verarbeiten, die Sie an client.method übergeben.
Lassen Sie es uns zuerst in Ruby tun. Dieses Mal werde ich method_missing verwenden, da ich nicht nur die Codemenge reduzieren, sondern auch dynamisch unbekannten Spezifikationen entsprechen möchte.
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
Wenn Sie es ausführen, sieht es so aus
"hoge"
[]
"fuga"
[1, 2, 3]
"piyo"
[]
"piyopiyo"
Als nächstes kommt PHP. Verwenden Sie `__ call
`. Ich erinnerte mich daran, als ich bei der Arbeit schrieb ~~ als es geschrieben wurde ~~. In Kombination mit Reflection fühlt es sich gut an. Für statische Methoden gibt es eine andere Methode namens "__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");
Wenn ich es mit cli starte, sieht es so aus
string(4) "hoge"
array(0) {
}
string(4) "fuga"
array(1) {
[0]=>
string(7) "fugaarg"
}
Wenn Sie es zu oft verwenden, ist der Code in der Regel schwer zu lesen. Verwenden Sie es systematisch.
Recommended Posts