---
sidebar_position: 11
title: "Patterns"
---

Esta página documenta os padrões de projeto identificados no código da plataforma. Para cada pattern: o que é, onde aparece, o que resolve, diagrama de funcionamento, exemplo do código real, alternativas consideradas e tradeoffs.

---

## Registry

### O que é

Um registro centralizado que mapeia identificadores para objetos ou funções, permitindo localizar e carregar componentes sem dependência direta entre módulos.

Referência externa: https://martinfowler.com/eaaCatalog/registry.html

### Onde aparece no código

- `app/src/config/gameRegistry.js` - registro de atividades de programação.
- `app/src/atividades/letramento/letramentoRegistry.js` - registro de atividades de letramento.

### O que resolve

O sistema precisa listar, filtrar e carregar atividades sem que os módulos de interface conheçam cada atividade diretamente. O registro é o único ponto de entrada para essa informação.

### Como funciona

```mermaid
graph LR
    A[Interface / Listagem] -->|consulta| R[Registry]
    R -->|retorna metadados| A
    A -->|lazy import sob demanda| M[Módulo da Atividade]
```

### Exemplo do código real

```javascript
// app/src/config/gameRegistry.js
export const games = [
  {
    id: 'aspirador',
    title: 'Aspirador',
    component: () => import('../atividades/programacao/aspirador/Aspirador.jsx'),
    // ...
  },
  // ...
];
```

### Alternativas

- **Importação direta**: simples, mas cria acoplamento rígido e dificulta extensão.
- **Backend com API de catálogo**: mais flexível para escala, mas desnecessário para a quantidade atual de atividades.

### Tradeoffs

| Vantagem | Limitação |
|---|---|
| Ponto único de extensão | Registro precisa ser atualizado manualmente ao adicionar atividade |
| Lazy loading integrado | Sem validação em tempo de compilação da entrada |

---

## Observer / Pub-Sub

### O que é

Um mecanismo onde componentes emitem eventos sem saber quem vai consumi-los. Quem tem interesse em um evento se inscreve e reage quando ele ocorre.

Referências externas:
- Observer: https://refactoring.guru/design-patterns/observer
- Publisher-Subscriber: https://learn.microsoft.com/en-us/azure/architecture/patterns/publisher-subscriber

### Onde aparece no código

- `app/src/utils/gameEvents.js` - barramento de eventos para atividades de programação.
- `app/src/utils/letramentoEvents.js` - barramento de eventos para atividades de letramento.

### O que resolve

O runtime da atividade e a interface React precisam se comunicar sem acoplamento direto. O runtime emite eventos (ex.: fase concluída) e a interface reage sem estar importada no runtime.

### Como funciona

```mermaid
sequenceDiagram
    participant R as Runtime da Atividade
    participant B as Event Bus
    participant C as Contexto React

    R->>B: emit('fase:concluida', dados)
    B->>C: notifica todos os ouvintes
    C->>C: atualiza estado
```

### Exemplo do código real

```javascript
// app/src/utils/gameEvents.js
const gameEventBus = new EventTarget();

export function emitGameEvent(type, detail) {
  gameEventBus.dispatchEvent(new CustomEvent(type, { detail }));
}

export function onGameEvent(type, handler) {
  gameEventBus.addEventListener(type, handler);
  return () => gameEventBus.removeEventListener(type, handler);
}
```

### Alternativas

- **Callbacks diretos**: mais simples, mas cria acoplamento bidirecional.
- **Estado compartilhado via Context**: possível, mas força re-render desnecessário para eventos transitórios.
- **Redux / Zustand**: justificável se o estado global crescer muito.

### Tradeoffs

| Vantagem | Limitação |
|---|---|
| Desacoplamento total entre emissor e consumidor | Difícil rastrear fluxo em debug |
| Múltiplos consumidores sem alterar o emissor | Sem tipagem estática dos eventos por padrão |

---

## Provider com React Context

### O que é

Um mecanismo do React que compartilha estado em uma árvore de componentes sem passar props manualmente por cada nível.

Referência externa: https://react.dev/reference/react/createContext

### Onde aparece no código

- `app/src/contexts/GameStateContext.jsx` - estado da sessão de execução.
- `app/src/contexts/GameProgressContext.jsx` - progresso de fases por atividade.
- `app/src/contexts/LetramentoStateContext.jsx` - estado da execução de letramento.
- `app/src/contexts/EditorContext.jsx` - estado do editor (blockly/code).

### O que resolve

Vários componentes em níveis diferentes da árvore precisam ler e modificar o mesmo estado (ex.: fase atual, modo do editor). Sem Context, as props precisariam ser passadas por vários níveis intermediários que não as usam.

### Como funciona

```mermaid
graph TD
    P[Provider
no topo da árvore] --> A[Componente A]
    P --> B[Componente B]
    A --> C[Componente C
consume contexto]
    B --> D[Componente D
consume contexto]
```

### Exemplo do código real

```javascript
// app/src/contexts/GameStateContext.jsx
export const GAME_STATES = {
  IDLE: 'idle',
  RUNNING: 'running',
  SUCCESS: 'success',
  FAILURE: 'failure',
};

export const GameStateContext = createContext(null);

export function GameStateProvider({ children }) {
  const [gameState, setGameState] = useState(GAME_STATES.IDLE);
  // ...
  return (
    <GameStateContext.Provider value={{ gameState, setGameState }}>
      {children}
    </GameStateContext.Provider>
  );
}
```

### Alternativas

- **Prop drilling**: funciona para árvores rasas, mas escala mal.
- **Zustand / Jotai**: mais leves e sem boilerplate de Provider, indicados se o número de contextos crescer muito.
- **Redux**: overhead justificado apenas para apps com lógica de estado muito complexa.

### Tradeoffs

| Vantagem | Limitação |
|---|---|
| Nativo do React, sem dependência extra | Re-renders em todos os consumidores ao atualizar |
| Fácil de testar com wrappers | Aninhamento excessivo de Providers |

---

## Factory

### O que é

Uma função ou classe que centraliza a criação de objetos com configuração específica, evitando que o código cliente precise conhecer os detalhes de construção.

Referência externa: https://refactoring.guru/design-patterns/factory-method

### Onde aparece no código

- `app/src/services/createStorageService.js` - cria serviços de storage com chave e estrutura pré-definidas.
- `app/src/hooks/usePhaser.js` - recebe `gameFactory`, uma função que constrói a configuração Phaser da atividade.

### O que resolve

Cada atividade precisa de um serviço de storage configurado com sua chave específica. Sem Factory, cada atividade repetiria o mesmo código de configuração.

### Como funciona

```mermaid
graph LR
    A[Atividade] -->|passa chave e schema| F[createStorageService]
    F -->|retorna| S[Serviço configurado
get / set / clear]
```

### Exemplo do código real

```javascript
// app/src/services/createStorageService.js
export function createStorageService(key, defaultValue) {
  return {
    get: () => JSON.parse(localStorage.getItem(key)) ?? defaultValue,
    set: (value) => localStorage.setItem(key, JSON.stringify(value)),
    clear: () => localStorage.removeItem(key),
  };
}
```

### Alternativas

- **Instância direta**: sem abstração, mais verboso e duplicado.
- **Classe base com herança**: mais pesado para o que é necessário aqui.

### Tradeoffs

| Vantagem | Limitação |
|---|---|
| Elimina repetição de código de storage | Contrato não tem tipagem estática |
| Fácil de substituir a implementação | Pouco ganho se a estrutura de cada storage for muito diferente |

---

## Template Method

### O que é

Define o esqueleto de um algoritmo na classe base e deixa que subclasses implementem as etapas variáveis, sem alterar a estrutura geral.

Referência externa: https://refactoring.guru/design-patterns/template-method

### Onde aparece no código

- `app/src/shared/BaseGameScene.js` - define o ciclo de vida de execução de uma atividade com Phaser.
- Cada `game.js` em `app/src/atividades/programacao/*/` sobrescreve os hooks de ciclo de vida.

### O que resolve

Todas as atividades de programação compartilham o mesmo ciclo de execução (iniciar, resetar, concluir, falhar), mas cada uma tem comportamento diferente em cada etapa. O Template Method evita duplicação dessa estrutura.

### Como funciona

```mermaid
classDiagram
    class BaseGameScene {
        +run()
        +reset()
        +onBeforeRun()
        +onReset()
        +onSuccess()
        +onFailure()
    }
    class AspiradorScene {
        +onBeforeRun()
        +onReset()
        +onSuccess()
    }
    class SemaforoScene {
        +onBeforeRun()
        +onSuccess()
        +onFailure()
    }
    BaseGameScene <|-- AspiradorScene
    BaseGameScene <|-- SemaforoScene
```

### Exemplo do código real

```javascript
// app/src/shared/BaseGameScene.js (simplificado)
class BaseGameScene extends Phaser.Scene {
  run() {
    this.onBeforeRun();
    this.interpreter.run();
  }
  reset() {
    this.onReset();
  }
  // Hooks sobrescritos pelas subclasses:
  onBeforeRun() {}
  onReset() {}
  onSuccess() {}
  onFailure() {}
}
```

### Alternativas

- **Composição com hooks React**: válido para comportamentos menores, mas não se aplica bem ao ciclo de vida do Phaser.
- **Callbacks/funções injetadas**: funcional, mas perde o benefício da herança de estado da cena.

### Tradeoffs

| Vantagem | Limitação |
|---|---|
| Garante que todas as atividades seguem o mesmo ciclo | Herança pode dificultar testes isolados |
| Reduz duplicação de orquestração | Subclasse precisa conhecer a classe base |

---

## Adapter

### O que é

Converte a interface de um sistema (ou protocolo) em outra que o sistema atual consegue consumir, sem modificar nenhum dos dois lados.

Referência externa: https://refactoring.guru/design-patterns/adapter

### Onde aparece no código

- `app/src/components/letramento/AtividadeRuntimeFrame.jsx` - converte mensagens `postMessage` do iframe em eventos internos do `letramentoEventBus`.

### O que resolve

As atividades de letramento rodam em iframe isolado e se comunicam via `window.parent.postMessage`. O React não entende esse protocolo nativamente - o Adapter faz a tradução para o barramento de eventos interno.

### Como funciona

```mermaid
graph LR
    A["Atividade HTML
(iframe)"] -->|"postMessage({ type: 'success' })"| AD["AtividadeRuntimeFrame
(Adapter)"]
    AD -->|"emit('atividade:success')"| B[letramentoEventBus]
    B --> C[LetramentoStateContext]
```

### Exemplo do código real

```javascript
// app/src/components/letramento/AtividadeRuntimeFrame.jsx (simplificado)
useEffect(() => {
  const handler = (event) => {
    if (event.source !== iframeRef.current?.contentWindow) return;
    const { type, score } = event.data;
    emitLetramentoEvent(`atividade:${type}`, { score });
  };
  window.addEventListener('message', handler);
  return () => window.removeEventListener('message', handler);
}, []);
```

Referências externas:
- postMessage: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
- iframe sandbox: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox

### Alternativas

- **Comunicação direta via ref do iframe**: possível, mas viola o isolamento do sandbox.
- **Servidor intermediário (WebSocket)**: excessivo para o escopo atual.

### Tradeoffs

| Vantagem | Limitação |
|---|---|
| Isola completamente a atividade HTML do React | Validação de origem precisa ser mantida para evitar injeção |
| Permite qualquer tecnologia dentro do iframe | Contrato `postMessage` é implícito e pode divergir |

---

## State Machine

### O que é

Um modelo que define estados possíveis de um sistema e as transições válidas entre eles, usando enums em vez de flags booleanas soltas.

Referência externa: https://refactoring.guru/design-patterns/state

### Onde aparece no código

- `GAME_STATES` em `app/src/contexts/GameStateContext.jsx`
- `ATIVIDADE_STATES` em `app/src/contexts/LetramentoStateContext.jsx`

### O que resolve

A execução de uma atividade tem estados interdependentes: não faz sentido exibir "sucesso" se a atividade nem começou. Com enums explícitos, o estado inválido é identificável em leitura de código.

### Como funciona

```mermaid
stateDiagram-v2
    [*] --> idle
    idle --> running : usuário executa
    running --> success : validação passou
    running --> failure : validação falhou
    success --> idle : resetar
    failure --> idle : resetar
```

### Exemplo do código real

```javascript
// app/src/contexts/GameStateContext.jsx
export const GAME_STATES = {
  IDLE: 'idle',
  RUNNING: 'running',
  SUCCESS: 'success',
  FAILURE: 'failure',
};
```

### Alternativas

- **Flags booleanas**: `isRunning`, `isSuccess`, etc. Funciona, mas permite estados impossíveis como `isRunning = true` e `isSuccess = true` ao mesmo tempo.
- **XState**: biblioteca dedicada a state machines com visualização e validação. Justificada para fluxos mais complexos.

### Tradeoffs

| Vantagem | Limitação |
|---|---|
| Elimina estados impossíveis | Exige disciplina para não usar flags paralelas |
| Fácil de ler em code review | Sem enforcement de transições em tempo de execução |

---

## Strategy

### O que é

Permite trocar o algoritmo ou comportamento de um componente em tempo de execução, mantendo a interface externa estável.

Referência externa: https://refactoring.guru/design-patterns/strategy

### Onde aparece no código

- Seleção de editor em `app/src/contexts/EditorContext.jsx` - alterna entre modo `blockly` e modo `code`.
- Validadores por fase em `app/src/atividades/programacao/*/validation/` - cada fase pode ter regra diferente.

### O que resolve

O editor pode funcionar em modo visual (Blockly) ou em modo código (CodeMirror). As atividades precisam validar condições diferentes por fase. Em ambos os casos, o contexto que usa essas estratégias não precisa mudar.

### Como funciona

```mermaid
graph TD
    EC[EditorContext] -->|editorType === 'blockly'| BL[BlocklyEditor]
    EC -->|editorType === 'code'| CM[CodeMirrorEditor]
    AT[Atividade] -->|fase atual| VF[Validador da Fase]
    VF -->|regras específicas| R[Resultado: sucesso/falha]
```

### Alternativas

- **Condicional inline**: `if (type === 'blockly') ... else ...` - funciona para dois casos, mas escala mal.
- **Mapa de componentes**: variação do Strategy, explícita e fácil de estender.

### Tradeoffs

| Vantagem | Limitação |
|---|---|
| Adicionar novo editor/validador não exige alterar o contexto | Contrato entre estratégia e contexto precisa ser mantido |
| Testável de forma isolada | Pode ser over-engineering para dois casos fixos |
