Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

[Dúvida] atributos privados

Tenho uma classe Task, essa classe tem um atributo $message que pode ser editado apenas se o status for 'pending', então criei uma classe para cada status, todas as classes tem o método editMessage(), o problema é: Como modificar $message sem ter que tornar publico o atributo?

class Task
{
    private string $message;
    private TaskState $state;

    public function __construct(string $message)
    {
        $this->state = new TaskPendingState($this);
        $this->message = $message;
    }

    public function setState(TaskState $state): void
    {
        $this->state = $state;
    }

    public function getState(): TaskState
    {
        return $this->state;
    }

    public function editMessage(string $message): void
    {
        // !!! como fazer isso funcionar sem tornar $this->message publico?
        $this->state->editMessage($message);
    }

    public function getMessage(): string
    {
        return $this->message;
    }
}
4 respostas
solução!

minha solução foi essa

abstract class TaskState
{
    protected Task $task;

    public function __construct(Task $task)
    {
        $this->task = $task;
    }

    abstract public function editMessage(string &$message, string $newMessage): void;
}
class Task
{
    private string $message;
    private TaskState $state; // pending, done, trash

    public function __construct(string $message)
    {
        $this->state = new TaskPendingState($this);
        $this->message = $message;
    }

    public function setState(TaskState $state): void
    {
        $this->state = $state;
    }
    
    public function getState(): TaskState
    {
        return $this->state;
    }

    public function editMessage(string $message): void
    {
        $this->state->editMessage($this->message, $message);
    }

    public function getMessage(): string
    {
        return $this->message;
    }
}

Você pode abordar isso permitindo que as classes de estado tenham acesso ao atributo message da classe Task sem torná-lo público. Para fazer isso, você pode adicionar um método protegido setMessage na classe Task e chamar esse método nas classes de estado. Aqui está uma possível implementação:

class Task
{
    private string $message;
    private TaskState $state;

    public function __construct(string $message)
    {
        $this->state = new TaskPendingState($this);
        $this->message = $message;
    }

    public function setState(TaskState $state): void
    {
        $this->state = $state;
    }

    public function getState(): TaskState
    {
        return $this->state;
    }

    protected function setMessage(string $message): void
    {
        $this->message = $message;
    }

    public function editMessage(string $message): void
    {
        $this->state->editMessage($message);
    }

    public function getMessage(): string
    {
        return $this->message;
    }
}

abstract class TaskState
{
    protected Task $task;

    public function __construct(Task $task)
    {
        $this->task = $task;
    }

    abstract public function editMessage(string $message): void;
}

class TaskPendingState extends TaskState
{
    public function editMessage(string $message): void
    {
        // Apenas permite editar se o status for 'pending'
        $this->task->setMessage($message);
    }
}

// Exemplo de uso
$task = new Task('Mensagem inicial');
echo $task->getMessage(); // Saída: Mensagem inicial

$task->editMessage('Nova mensagem'); // Edita a mensagem apenas se o status for 'pending'

echo $task->getMessage(); // Saída: Nova mensagem

Neste exemplo, o método setMessage é protegido e só pode ser acessado pelas classes filhas. A classe TaskPendingState então chama esse método para editar a mensagem apenas quando o status for 'pending'. Isso mantém o atributo message privado e controla a edição por meio dos estados.

Opa Carlos, vou testar

Carlos, não funcionou, TaskState não é filha da classe Task, então não tem como ela ter acesso aos métodos protected