Tengo un módulo C++ que necesita obtener información de otras clases, sin conocer esas clases. El enfoque obvio es usar interfaces.¿Tiene una interfaz con muchos métodos virtuales? ¿O tener muchas interfaces con solo 1 método virtual?
Déjeme darle un ejemplo. Supongamos que tengo una biblioteca que administra libros, y todos los libros tienen sus propias características y funcionalidades, y para permitir que la biblioteca obtenga una característica de un libro o ejecute una función, el libro necesita implementar una interfaz. De esta manera:
class Library
{
public:
void addBook(IBook &book);
};
class IBook
{
public:
string getAuthor() = 0;
string getTitle() = 0;
string getISBNCode() = 0;
size_t getNofPages() = 0;
size_t getNofImages() = 0;
double getPrice() = 0;
void printBook() = 0;
void convertToPdf() = 0;
};
Desafortunadamente, no tiene sentido implementar todos estos métodos para todo tipo de libros.
- Algunos libros no tienen imágenes (por lo que no quiero poner en práctica getNofImages())
- Algunos libros no tienen un código ISBN
- Algunos libros no se pueden comprar, por lo no tienen un precio
- Algunos libros no se pueden imprimir
- Algunos libros no se pueden convertir a PDF
porque sólo tengo 1 interfaz, estoy obligado a poner en práctica todo lo necesario para todos los libros devuelven 0, devuelven "" o no hacen nada en la implementación si es irrelevante.
Una alternativa podría ser la de dividir estas interfaces en muchas interfaces, así:
class IBook
{
public:
string getAuthor() = 0;
string getTitle() = 0;
size_t getNofPages() = 0;
};
class IISBNGetter
{
public:
string getISBNCode() = 0;
};
class IImagesGetter
{
public:
size_t getNofImages() = 0;
};
class IBuyable
{
public:
double getPrice() = 0;
};
class IPrintable
{
public:
void printBook() = 0;
};
class IConvertible
{
public:
void convertToPdf() = 0;
};
clases libro, entonces sólo tienen que poner en práctica las interfaces que realmente quieren apoyar.
Adición de un libro a la biblioteca a continuación, se convierte en algo parecido a esto:
bookid = myLibrary->addBook (myBook);
myLibrary->setISBNGetter (bookid, myBook);
myLibrary->setImageGetter (bookid, myBook);
myLibrary->setBuyable (bookid, myBook);
La ventaja de tener diferentes interfaces es que está claro para la biblioteca que apoya lo que, y nunca tiene el riesgo de llamar a algo eso simplemente no es compatible.
Sin embargo, dado que cada libro puede tener cualquier combinación posible de características/funcionalidades, termino con muchas interfaces con solo 1 método.
¿No hay una mejor manera de organizar las interfaces para obtener algo como esto?
También estaba pensando en usar expresiones Lambda pero detrás de las pantallas esto es casi lo mismo que tener muchas interfaces con solo 1 método.
¿Alguna idea?
Totalmente de acuerdo, los libros son, naturalmente, considerados potencialmente tener ISBN y precio. Dado un libro en particular, me gustaría preguntar si se puede comprar y cuál es el precio, si tiene un ISBN y cuál es ese valor de ISBN ... esas operaciones semánticamente pertenecen a la interfaz 'IBook'. Desde un punto de vista diferente, tener una interfaz 'ISBNGetter' parece implicar que diferentes objetos pueden tener ISBN, pero solo los libros lo tienen. No hay ninguna circunstancia bajo la cual usted use las interfaces adicionales en un objeto que no es también un 'IBook'. –
@dribeas: sí, aunque tener 'IISBNGetter' derivado de' IBook' podría ser más problemático de lo que vale, incluso si fuera con interfaces adicionales. Creo que ISBN-13 es compatible con UPC, sin embargo. Si es así, entonces 'IUPCGetter' sería más general, e 'IBuyable' ciertamente lo es. 'IBuyable' podría ser una interfaz que valga la pena tener, independientemente de si está definido que todos los libros lo implementan, o solo algunos. –