Abstract Class in Python, how to choose implementation

4

I'm learning python and trying to do a program where I have an abstract class and two subclasses that implement such. I need to make another class that will choose which implementation to use depending on the user, but I can not do that. If someone can point me some study material for this part of OOP would help me a lot! I did not find anything to help me in this part of the class.

Follow the part of the code. The BaseDifferent that I do not know how to do.

class Dificultador(object):
#classe abstrata que vai ser super classe de DificultadorNivel e DificultadorTipo
from abc import ABCMeta, abstractmethod
__metaclass__ = ABCMeta
@abstractmethod
def Sort(self, expressoes):
    pass

class DificultadorNivel(Dificultador):#Faz um sort da lista de expressoes em niveis
def Sort(self, expressoes):
    expressoes = FonteDeExpressoes().lista()
    expnivel = sorted(expressoes, key=lambda x: x.nivel)
    return expnivel

class DificultadorTipo(Dificultador):#Faz um sort da lista de expressoes em tipo
def Sort(self, expressoes):
    expressoes = FonteDeExpressoes().lista()
    exptipo = sorted(expressoes, key=lambda x: x.tipo)
    return exptipo

class BaseDificultador(Dificultador):
#Funciona como um switch de seleção para escolha do sort
    
asked by anonymous 25.07.2016 / 21:39

2 answers

4

The simplest way to choose which object to instantiate depending on some condition of the program is to use a function for it.

The name "complicated" is "factory function" or "factory method". In some other OOP languages, you have to use a factory function that implies some complication since the function itself has to stay in another class (sometimes built artificially just for that), but in Python it's quite straightforward:

def obtem_dificultador(parametros):
    if (condicao):
          return DificultadorNivel(parametros)
    else:
        return DificultadorTipo(parametros)  

Or, because classes are simply objects that are callable to instantiate, your class selection may simply return the class - which will be instantiated with the desired parameters only by the caller. Furthermore, if you are multiple classes, you can reference your classes in a data structure, such as a dictionary, which may allow you to get the desired class cleaner than a long if / elif / else string.

Of course Python is dynamic enough for you to to change the class, or the subclass, of a subclass within the instantiating mechanism itself (usually in the __new__ method) - but there, as it is in @Gigano's answer, it is not considered good practice. Factory functions are good.

In Python it is also possible, for classes defined in Python code, to directly change the __class__ attribute of an already instantiated object - effectively changing the class of an existing object. (Of course, such a practice would be defensible, not for demonstration purposes.) The object's attributes and initialization were all of the old class.

If it is a large project, and you need sophisticated mechanisms to choose the class, it may be the case that Zope Component Architecture - a componentization framework (which has only the name "Zope") - is not the Zope integer) link

(The implementation of the correct form of the abstract class is as it is in the Gypsy's answer - but in Python it's not that much needed - unless you really have a large structure and risk getting in the way each class needs to implement or not (abstract class subclasses that are missing methods will give error the moment their declaration is processed))

    
26.07.2016 / 17:24
3

Abstract classes in Python are implemented using the module abc . The correct would be something like this (considering Python 3.4 and above):

from abc import ABC, abstractmethod

class Dificultador(ABC):
    '''classe abstrata que vai ser super classe de DificultadorNivel e DificultadorTipo'''
    @abstractmethod
    def Sort(self, expressoes):
        pass

The other classes look like this:

class DificultadorNivel(Dificultador):
    '''Faz um sort da lista de expressoes em niveis'''
    def Sort(self, expressoes):
        expressoes = FonteDeExpressoes().lista()
        expnivel = sorted(expressoes, key=lambda x: x.nivel)
        return expnivel

class DificultadorTipo(Dificultador):
    '''Faz um sort da lista de expressoes em tipo'''
    def Sort(self, expressoes):
        expressoes = FonteDeExpressoes().lista()
        exptipo = sorted(expressoes, key=lambda x: x.tipo)
        return exptipo

You do not need to implement BaseDificultador . This goes against the SOLID .

    
25.07.2016 / 21:47