Вызов метода в классе A в зависимости от типа параметра - PullRequest
4 голосов
/ 18 декабря 2009
class Class1(object):
    ...

class Class2(object):
    ...

class Class3(object):
    ...

class A(object):
    def _methA(parm1, parm2)
        ...

    def _methB(parm1, parm2)
        ...

    def _methC(parm1, parm2)
        ...

    def manager(parm1, method, params)
        ...
        if parm1.__class__.__name__==Class1.__name__:
            response = _methA(parm1, params)
        elif parm1.__class__.__name__==Class2.__name__:
            response = _methB(parm1, params)
        elif io_source.__class__.__name__==Class3.__name__:
            response = _methC(parm1, params)
        else:
            raise Exception, "Unsupported parm1"
        ...

Мне не понравилось, как блок if/elif в manager() выглядел и реорганизовал его так:

def manager(parm1, method, params)
    ...
    try:
        response = {
                Class1.__name__: lambda parm1, parms: _methA(parm1, parms),
                Class2.__name__: lambda parm1, parms: _methB(parm1, parms),
                Class3.__name__: lambda parm1, parms: _methC(parm1, parms)
                }[parm1.__class__.__name__](parm1, parms)
    except KeyError:
        raise Exception, "Unsupported parm1" 

Но тот факт, что код все еще просматривает имена классов, беспокоит меня - я действительно не знаю, как объяснить, почему ... Должно ли это беспокоить меня? Есть ли лучший способ написать код для вызова метода в классе A, который в зависимости от класса одного из его параметров вызывает вызов различных методов в A?

PS. Извините за надуманный пример, но размещение реального кода сделало бы вопрос еще более запутанным. Я пытался отогнать вопрос в его сути ...

Ответы [ 4 ]

5 голосов
/ 18 декабря 2009

Это один из многих неправильных способов реализации полиморфизма. Вы никогда не должны смотреть на имена классов. Просмотр имен классов должен вас беспокоить, потому что это означает, что вы не делегировали ответственность правильно.

Переместите каждый метод в соответствующий класс.

class Class1(object):
    def method( self, theA, params ):
        theA.methA( params )

class Class2(object):
    def method( self, theA, params ):
        theA.methB( params )

class Class3(object):
    def method( self, theA, params ):
        theA.methC( params )

class A(object):
    def methA(parm1, parm2)
        ...

    def methB(parm1, parm2)
        ...

    def methC(parm1, parm2)
        ...

    def manager(parm1, method, params)
        ...
        param1.method( self, params )
1 голос
/ 18 декабря 2009

Вы пытаетесь эмулировать то, что фанаты языка называют " множественная отправка " или "мультиметоды" Ссылка на статью в Википедии имеет хорошее обсуждение, включая примеры Python.

0 голосов
/ 18 декабря 2009

Обычно я делаю это при обработке сообщений, поэтому у меня нет тонны ifs ... но он все еще использует имена классов.

Вид полиморфизма бедного человека - но, как сказал С. Лотт, Python поддерживает настоящий полиморфизм, так почему бы не использовать его: p

class Handler(object):
    # .. stuff

    def dispatch(self, msg):
        handlername = "on_%s" % type(msg)
        return getattr(self, handlername, 'on_missing_handler')(msg)

    def on_SomeClass(self, msg):
        # msg is of SomeClass here ..

    def on_SomeOtherClass(self, msg):
        # msg is of SomeOtherClass here ..

    def on_missing_handler(self, msg):
        # there is no other handler for msg
0 голосов
/ 18 декабря 2009

Я бы предпочел

if isinstance(parm1, Class1):
    _methA(parm1, params)
elif isinstance(parm1, Class2):
    _methB(parm1, params)
elif isinstance(parm1, Class3):
    _methC(parm1, params)

но это все еще пахнет недостатком дизайна. :)

Может быть, все три класса ClassX должны иметь один метод meth(params), тогда ваш менеджер может просто вызвать parm1.meth(params).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...