design de software
talvez tu te interesse por desenvolvimento-de-software?
é importante conhecer padrões de design de software porque eles nos dão uma noção de como resolver problemas comuns de uma maneira 'eficiente'. digo 'eficiente' porque não estou aqui pra definir regras - o que funciona é, por si só, eficiente.
existem 3 tipos:
- criacionais (singleton, builder, factory) - mais flexibilidade pra criar objetos
- estruturais (facade, adapter) - lidam com o relacionamento entre objetos. são como blueprints pra construir coisas maiores a partir de peças individuais
- comportamentais (strategy, observer) - lidam com a comunicação entre objetos: como interagem e como dividem as 'responsabilidades'
padrões criacionais
singleton
- cria uma única instância de uma classe (tipo um logger ou uma conexão) e compartilha por toda a aplicação
- normalmente acessada globalmente
- previne múltiplas cópias de recurso/estado (+)
- fácil de usar em qualquer lugar (+)
- controle melhor sobre recursos (+)
- teste mais complicado, difícil de mockar (-)
- é uma variável global, nem sempre se aplica (-)
o gerador de números aleatórios numa simulação sequencial gaussiana. tu quer uma só fonte de aleatoriedade com uma semente (seed). se cada bloco criar o próprio gerador, perde a reprodutibilidade e a sequência fica enviesada. uma instância única = a mesma realização toda vez que rodas com a mesma semente.
builder
- útil pra criar objetos com muitas partes opcionais ou configurações - tipo montar um hambúrguer customizável ou construir uma vizinhança
- usa quando quer montar o objeto passo a passo ou quando tem mais de uns 10 parâmetros
- melhor leitura e representação mais flexível (+)
- pode virar overhead em objeto simples, e é mal usado quando não é bem estruturado (-)
montar os parâmetros de uma krigagem. tem um monte de coisa: variograma, raios da elipsoide de busca, mín/máx de amostras, octantes, discretização do bloco... o builder vai adicionando cada peça (
.com_variograma(...).com_busca(...).com_bloco(...)) e só no final entrega o objeto pronto. é basicamente o que um arquivo.parde programa GSLIB faz, só que em código.
factory
- provê uma interface pra criar objetos, mas deixa as subclasses decidirem qual classe instanciar (tu escolhe o que vai ser feito com algo tipo um switch, passando um tipo)
- usa quando a criação envolve setup complexo ou quando cria tipos relacionados
- mais complicado que um construtor normal (-)
- acopla a criação, o que confunde quando a ideia era abstrair (-)
uma factory de estimadores. passa o nome (
"krigagem_ordinaria","krigagem_simples","idw","vizinho_mais_proximo") e ela devolve o objeto certo, todos com o mesmo método.estimar(ponto). o resto do código não precisa saber qual foi instanciado.
padrões estruturais
facade
- provê uma interface simples pra um sistema complexo de classes, libs ou subsistemas
- vs factory: não é sobre criar, é sobre a relação entre os objetos
- esconde a complexidade do usuário e deixa o sistema mais fácil de usar (+)
- vira "god object" se faz e sabe demais (-)
uma função
estimar_bloco(coords)que por baixo faz declustering, busca de vizinhos, monta e resolve o sistema linear de krigagem e devolve o teor + variância. quem chama vê uma função só; toda a álgebra fica escondida.
adapter
- permite que interfaces incompatíveis trabalhem juntas, servindo de ponte entre elas
- ajuda a usar código legado, lib de terceiros ou api num sistema novo
teus drillholes vêm em formatos diferentes - GSLIB, CSV, banco de dados. cada um tem um adapter que converte pro mesmo formato que o estimador entende. troca a fonte sem mexer no resto.
padrões comportamentais
strategy
- deixa tu definir uma família de algoritmos, colocar cada um numa classe separada e trocar entre eles em tempo de execução
- muda o comportamento dinamicamente sem mexer na classe principal
- segue o princípio aberto/fechado (aberto pra extensão, fechado pra modificação)
- tipo trocar entre carro e a pé num app de navegação - mesma interface, comportamento diferente
- separa a lógica em classes e chama na classe principal (usa interface)
o algoritmo de interpolação. a mesma rotina que percorre o grid chama
interpolar(ponto), mas a estratégia por trás pode ser krigagem, IDW ou spline.
observer
- deixa vários objetos (observers) escutarem e reagirem a mudanças em outro objeto (subject)
- cria uma dependência um-pra-muitos
- usa quando uma mudança deve avisar os outros automaticamente
- código:
button.add_listener(on_click)
monitorar uma simulação longa. a cada bloco estimado, o subject avisa os inscritos: a barra de progresso atualiza, o logger registra e o checkpoint salva o estado em disco. nenhum deles precisa conhecer os outros - só escutam o evento "bloco pronto".