Como evitar arrastar argumentos de função para função

5

Quando faço o layout do código, gosto de começar com uma exibição de alto nível e, em seguida, começo a delegar a computação real para a classe ou funções que possuem um pouco mais de detalhes. Então, nessas classes de funções, faço o mesmo, camada por camada, até chegar ao fundo onde tenho que fazer a ação 'real'.

Exemplo:

def build_table():
    legs = get_legs()
    plate = get_plate()
    return put_together(legs, plate)

def get_legs():
    legs = []
    for i in [0,1,2,3]:
        legs.append(get_leg_from_warehouse())
    return legs

def get_plate():
    plate = get_plate_from_warehouse()
    return finish_plate(plate)

def put_together(legs, plate):
    table = Table()
    for i in [0,1,2,3]:
       table.mount(legs[i])
    table.mount(plate)
    return table

class Table:
    self.component = []
    def mount(self, item):
        self.component.append(item)

Dessa forma, acho fácil pensar no layout e ocultar a complexidade. Eu principalmente tenho pequenos pedaços de código que são fáceis de entender.

A desvantagem disso é que quando eu descubro que preciso de uma informação disponível no topo da pilha, eu passo argumentos de função para função. No exemplo acima, eu poderia reunir 'parafusos' no topo, e então continuá-los passando para uma função onde eles são realmente perfurados na madeira. Isso faz com que não seja tão fácil modificar o código, e fiquei imaginando o que eu poderia fazer sobre isso. Neste exemplo, o código modificado ficaria assim:

def build_table():
    legs = get_legs()
    plate = get_plate()
    screws = get_screws()
    return put_together(legs, plate, screws)

def get_legs():
    legs = []
    for i in [0,1,2,3]:
        legs.append(get_leg_from_warehouse())
    return legs

def get_plate():
    plate = get_plate_from_warehouse()
    return finish_plate(plate)

def get_screws():
    drive_to_hardwarestore()
    screws = buy_screws()
    drive_home()
    return screws

def put_together(legs, plate, screws):
    table = Table()
    for i in [0,1,2,3]:
       table.mount(legs[i], screws)
    table.mount(plate, screws)
    return table

class Table:
    self.component = []
    def mount(self, item, screws):
        self.component.append((item, screws.pop()))

Então, além de adicionar o código para obter os parafusos, eu tive que modificar 4 linhas. Isso aumentaria linearmente com a quantidade de camadas.

Como posso refatorar? Por outro lado, como posso evitar isso em primeiro lugar? O meu processo de design está "errado"?

    
por Isaac 15.11.2013 / 07:36
fonte

1 resposta

7

So besides adding the code for getting screws, I had to modify 4 lines. This would increase linearly with the amount of layers.

Eu acho que isso é uma falácia. Quando você adiciona outro tipo de parte da tabela, você ainda terá apenas que alterar 4 linhas de código na sua "camada de construção do objeto". As camadas acima da camada "construção de objeto" em seu código funcionarão apenas com objetos "de tabela", sem modificações, contanto que não tenham que lidar com o novo tipo de peça. Você pode passar esse objeto de tabela através de um número arbitrário de camadas e não precisa alterar nada. E quando você encontra uma parte em seu código onde você tem que acessar seus parafusos, esse código pode simplesmente pedir o "objeto de tabela" para os parafusos.

É claro, quando o próprio processo de construção de objeto se torna mais complicado, e você pensa que tem "muita informação" lá, você pode considerar criar uma classe de fábrica (de tabela) para encapsular as construções. Dessa forma, é possível criar "parafusos", "pernas" e "placa" em um lugar, armazená-los em variáveis de membro da fábrica e obtê-los posteriormente na função "montar".

Portanto, enquanto o processo de construção for simples, atenha-se ao design e, se ficar mais complicado, use as classes de fábrica.

    
por 15.11.2013 / 09:28
fonte