Estoy tratando de seguir el principio DRY en mi programación tan duro como puedo. Recientemente he estado aprendiendo patrones de diseño en OOP y terminé repitiéndome bastante.
He creado un patrón de repositorio junto con los patrones de Factory y Gateway para manejar mi persistencia. Estoy usando una base de datos en mi aplicación, pero eso no debería importar, ya que debería poder cambiar la puerta de enlace y cambiar a otro tipo de persistencia si lo desea.
El problema que terminé creando para mí es que creo los mismos objetos para la cantidad de tablas que tengo. Por ejemplo, estos serán los objetos que necesito para manejar una tabla 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);
}
}
Entonces mi controlador se ve como
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));
}
}
Entonces pensé que estaba usando patrones de diseño correctamente y mantenía buenas prácticas, pero el problema con esto es que cuando agrego una nueva tabla, tengo que crear las mismas clases solo con otros nombres. Esto me hace sospechar que puedo estar haciendo algo mal.
Pensé en una solución donde, en lugar de interfaces, tenía clases abstractas que, usando el nombre de la clase, calculan la tabla que necesitan manipular, pero eso no parece ser lo correcto, ¿qué sucede si decido cambiar a un almacenamiento de archivos o memcache donde no hay tablas.
¿Estoy abordando esto correctamente, o hay una perspectiva diferente que debería mirar?