Eu tenho uma classe que configura uma matriz de nós e os conecta um ao outro em uma estrutura semelhante a um gráfico. É melhor:
- Mantenha a funcionalidade para inicializar e conectar os nós em uma função
- Tenha a funcionalidade de inicialização e conexão em duas funções diferentes (e tenha uma ordem dependente na qual as funções devem ser chamadas - embora tenha em mente que essas funções são privadas).
Método 1: (Ruim, porque uma função está fazendo duas coisas, mas mantém a funcionalidade dependente agrupada - os nós nunca devem ser conectados sem serem inicializados primeiro.)
init() {
setupNodes()
}
private func setupNodes() {
// 1. Create array of nodes
// 2. Go through array, connecting each node to its neighbors
// according to some predefined constants
}
Método 2: (Melhor no sentido de que é auto-documentado, MAS connectNodes () nunca deve ser chamado antes de setupNodes (), portanto, qualquer pessoa que trabalhe com os internos da classe precisa conhecer essa ordem.)
init() {
setupNodes()
}
private func setupNodes() {
createNodes()
connectNodes()
}
private func createNodes() {
// 1. Create array of nodes
}
private func connectNodes() {
// 2. Go through array, connecting each node to its neighbors
// according to some predefined constants
}
Animado para ouvir qualquer pensamento.
Respostas:
O problema com o qual você está lidando é chamado de acoplamento temporal
Você está certo em se preocupar com o quão compreensível esse código é:
Eu posso adivinhar o que está acontecendo lá, mas me diga se isso torna o que mais está acontecendo um pouco mais claro:
Isso tem o benefício adicional de ser menos acoplado à modificação de variáveis de instância, mas, para mim, ser legível é o número um.
Isso torna
connectNodes()
explícita a dependência de nós.fonte
Funções separadas , por dois motivos:
1. Funções privadas são privadas exatamente para esta situação.Sua
init
função é pública e sua interface, comportamento e valor de retorno é o que você precisa para se preocupar em proteger e mudar. O resultado que você espera desse método será o mesmo, independentemente da implementação usada.Como o restante da funcionalidade está oculto por trás dessa palavra-chave privada, ela pode ser implementada da maneira que você quiser ... para que você a torne agradável e modular, mesmo que um pouco dependa do outro chamado primeiro.
2. Conectar nós um ao outro pode não ser uma função privadaE se, em algum momento, você desejar adicionar outros nós à matriz? Você destrói a configuração que possui agora e reinicia-a completamente? Ou você adiciona nós à matriz existente e executa
connectNodes
novamente?Possivelmente
connectNodes
pode ter uma resposta sã se a matriz de nós ainda não tiver sido criada (lance uma exceção? Retorne um conjunto vazio? Você precisará decidir o que faz sentido para a sua situação).fonte
Você também pode descobrir (dependendo da complexidade de cada uma dessas tarefas) que essa é uma boa solução para dividir outra classe.
(Não tenho certeza se Swift funciona dessa maneira, mas com pseudo-código :)
Isso separa as responsabilidades de criar e modificar nós para separar classes:
NodeGenerator
apenas se preocupa em criar / recuperar nós, enquantoYourClass
apenas se preocupa em conectar os nós que ele recebe.fonte
Além de ser esse o objetivo exato dos métodos particulares, o Swift oferece a capacidade de usar funções internas.
Os métodos internos são perfeitos para funções que possuem apenas um site de chamada, mas parecem que não justificam serem funções privadas separadas.
Por exemplo, é muito comum ter uma função pública de "entrada" recursiva, que verifica pré-condições, configura alguns parâmetros e delega para uma função privada recursiva que faz o trabalho.
Aqui está um exemplo de como isso pode parecer neste caso:
Preste atenção em como eu uso valores e parâmetros de retorno para transmitir dados, em vez de alterar um estado compartilhado. Isso torna o fluxo de dados muito mais óbvio à primeira vista, sem a necessidade de pular para a implementação.
fonte
Toda função que você declara carrega o ônus de adicionar documentação e torná-la generalizada para que possa ser usada por outras partes do programa. Ele também carrega o ônus de entender como outras funções no arquivo podem estar usando-o para alguém ler o código.
Se, no entanto, não for usado por outras partes do seu programa, eu não o exporia como uma função separada.
Se o seu idioma suportar, você ainda pode ter uma função faz uma coisa usando funções aninhadas
O local da declaração é muito importante e, no exemplo acima, fica claro, sem a necessidade de mais pistas, que as funções internas devem ser usadas apenas dentro do corpo da função externa.
Mesmo se você as declarar como funções privadas, presumo que elas ainda estejam visíveis para o arquivo inteiro. Portanto, você precisará declará-los perto da declaração da função principal e adicionar alguma documentação que esclareça que eles devem ser usados apenas pela função externa.
Não acho que você precise fazer estritamente um ou outro. A melhor coisa a fazer varia caso a caso.
Dividi-lo em várias funções certamente adiciona uma sobrecarga de entendimento sobre por que existem três funções e como todas elas funcionam, mas se a lógica é complexa, essa sobrecarga adicionada pode ser muito menor do que a simplicidade introduzida ao quebrar a lógica complexa. em partes mais simples.
fonte
private
permite acesso somente no tipo de anexo (struct / class / enum), enquantofileprivate
permite acesso ao longo de todo o arquivo