Estou tentando seguir o princípio DRY na minha programação o máximo que posso. Recentemente, tenho aprendido padrões de design no OOP e acabei me repetindo bastante.
Eu criei um padrão de repositório junto com os padrões de fábrica e gateway para lidar com minha persistência. Estou usando um banco de dados no meu aplicativo, mas isso não deve importar, pois eu posso trocar o Gateway e alternar para outro tipo de persistência, se assim o desejar.
O problema que acabei criando para mim mesmo é que eu crio os mesmos objetos para o número de tabelas que tenho. Por exemplo, esses serão os objetos que eu preciso para manipular uma tabela comments
.
class Comment extends Model {
protected $id;
protected $author;
protected $text;
protected $date;
}
class CommentFactory implements iFactory {
public function createFrom(array $data) {
return new Comment($data);
}
}
class CommentGateway implements iGateway {
protected $db;
public function __construct(\Database $db) {
$this->db = $db;
}
public function persist($data) {
if(isset($data['id'])) {
$sql = 'UPDATE comments SET author = ?, text = ?, date = ? WHERE id = ?';
$this->db->prepare($sql)->execute($data['author'], $data['text'], $data['date'], $data['id']);
} else {
$sql = 'INSERT INTO comments (author, text, date) VALUES (?, ?, ?)';
$this->db->prepare($sql)->execute($data['author'], $data['text'], $data['date']);
}
}
public function retrieve($id) {
$sql = 'SELECT * FROM comments WHERE id = ?';
return $this->db->prepare($sql)->execute($id)->fetch();
}
public function delete($id) {
$sql = 'DELETE FROM comments WHERE id = ?';
return $this->db->prepare($sql)->execute($id)->fetch();
}
}
class CommentRepository {
protected $gateway;
protected $factory;
public function __construct(iFactory $f, iGateway $g) {
$this->gateway = $g;
$this->factory = $f;
}
public function get($id) {
$data = $this->gateway->retrieve($id);
return $this->factory->createFrom($data);
}
public function add(Comment $comment) {
$data = $comment->toArray();
return $this->gateway->persist($data);
}
}
Então meu controlador parece
class Comment {
public function view($id) {
$gateway = new CommentGateway(Database::connection());
$factory = new CommentFactory();
$repo = new CommentRepository($factory, $gateway);
return Response::view('comment/view', $repo->get($id));
}
}
Por isso, pensei que estava usando padrões de design corretamente e mantendo boas práticas, mas o problema é que, quando adiciono uma nova tabela, tenho que criar as mesmas classes apenas com outros nomes. Isso levanta suspeitas em mim de que posso estar fazendo algo errado.
Pensei em uma solução em que, em vez de interfaces, tinha classes abstratas que, usando o nome da classe, descobrem a tabela que precisam manipular, mas isso não parece a coisa certa a se fazer, e se eu decidir mudar para um armazenamento de arquivo ou memcache onde não há tabelas.
Estou abordando isso corretamente ou há uma perspectiva diferente que eu deveria estar olhando?