2 votes

Méthode pythonique d'extension d'un modèle de construction

Examinez les points suivants CDK en Python (pour cette question, il n'est pas nécessaire d'avoir des connaissances sur AWS et cela devrait être valable pour n'importe quel modèle de construction, j'utilise simplement CDK dans cet exemple car j'ai rencontré le problème en utilisant cette bibliothèque) :

from aws_cdk import aws_stepfunctions as step_fn
from aws_cdk import core

app = core.App()
state_machine = step_fn.Chain.start(
    step_fn.Pass(app, 'start')
).next(
    step_fn.Pass(app, 'foo1')
).next(
    step_fn.Pass(app, 'foo2')
).next(
    step_fn.Pass(app, 'bar')
)

Maintenant, si je dois réutiliser la construction

.next(
    step_fn.Pass(app, 'foo1')
).next(
    step_fn.Pass(app, 'foo2')
)

plusieurs fois, j'ai pu trouver ces approches.

  1. Envelopper le code dans une méthode

    def foo(chain: step_fn.Chain) -> step_fn.Chain: return chain.next( step_fn.Pass(app, 'foo1') ).next( step_fn.Pass(app, 'foo2') )

    This works but it destroys the readability of the chain as the calling order is inverted.

    state_machine = foo( step_fn.Chain.start( step_fn.Pass(app, 'start') ) ).next( step_fn.Pass(app, 'bar') )

    This is against the builder design to wrap mutability in the builder classes.

    state_machine = step_fn.Chain.start( step_fn.Pass(app, 'start') ) state_machine = foo(state_machine) state_machine = state_machine.next( step_fn.Pass(app, 'bar') )

  2. Singe Parcheando

Bien que la syntaxe soit apparemment agréable, elle semble sujette aux erreurs et constitue un cauchemar en termes de maintenabilité lorsqu'elle est appliquée à un projet réel avec plusieurs personnes travaillant sur le référentiel :

step_fn.Chain.foo = foo
state_machine = step_fn.Chain.start(
    step_fn.Pass(app, 'start')
).foo().next(
    step_fn.Pass(app, 'bar')
)

J'ai essayé de voir s'il y avait un moyen d'implémenter des classes de type pour les objets Python, mais je n'ai rien trouvé. J'ai trouvé dry-python mais je ne suis pas sûr qu'il puisse être utilisé pour les méthodes de classe. En Scala, classes implicites pourrait être utilisé pour avoir une syntaxe de constructeur fluide sans altérer aucun état global. Existe-t-il un moyen Pythonique de réaliser la même chose ?

Edit : J'ai découvert plus tard que la chaîne CDK permet d'ajouter d'autres chaînes, ce qui résout ce problème particulier. En général, si vous pouvez influencer la conception des constructeurs, il est probablement préférable d'ajouter une méthode extend etc. qui permet d'ajouter un autre constructeur au constructeur, ce qui facilite sa réutilisation pour ce type de scénarios.

2voto

Enzo Points 306

Il est possible d'intégrer l'ensemble dans une classe :

class ChainHelper:
    def __init__(self, app: core.App, chain: step_fn.Chain):
        self._app = app
        self._chain = chain

Cela vous permet de donner des noms descriptifs à vos opérations et de les réutiliser davantage :

class ChainHelper:
    def __init__(self, app: core.App, chain: step_fn.Chain):
        self._app = app
        self._chain = chain

    def pass_arg(self, arg: str):
        self._chain = self._chain.next(step_fn.Pass(self._app, arg))
        return self

    def pass_foo(self):
        self._chain = self._chain \
            .next(step_fn.Pass(self._app, 'foo1')) \
            .next(step_fn.Pass(self._app, 'foo2'))
        return self

Utilisation :

state_machine = ChainHelper(app=core.App(), chain=step_fn.Chain) \
    .pass_arg('start')  \
    .pass_foo()         \
    .pass_arg('bar')

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X