Para hacer que su código se acople libremente aquí hay algunas cosas simples para recordar:
Parte 1:
Técnicamente conocido como "Separación de preocupaciones". Cada clase tiene un rol específico, debe manejar la lógica de negocios o la lógica de la aplicación. Trate de mantenerse alejado de la clase que combina ambas responsabilidades. es decir, una clase que gestiona datos (a largo plazo) es la lógica de la aplicación, mientras que una clase que utiliza datos es la lógica de negocios.
Personalmente me refiero a esto (en mi propio pequeño mundo) como create it or use it
. Una clase debe crear un objeto o usar un objeto que nunca debe hacer ambas cosas.
Parte 2:
Cómo implementar la separación de preocupaciones.
Como punto de partida hay dos técnicas simples:
Nota: Los patrones de diseño no son absolutos.
Se supone que están personalizados para la situación, pero tienen un tema subyacente que es similar a todas las aplicaciones. Así que no mire los ejemplos a continuación y diga que debo seguir esto rígidamente; estos son solo ejemplos (y un poco artificiales).
Inyección de dependencia :
Aquí es donde pasa un objeto que usa una clase. El objeto que pasa basado en una interfaz para que su clase sepa qué hacer con él, pero no necesita saber la implementación real.
class Tokenizer
{
public:
Tokenizer(std::istream& s)
: stream(s)
{}
std::string nextToken() { std::string token; stream >> token;return token;}
private:
std::istream& stream;
};
Aquí inyectamos la secuencia en un Tokenizer. El tokenizer no sabe de qué tipo es la secuencia, siempre que implemente la interfaz de std :: istream.
Patrón de localizador de servicio :
El patrón del localizador de servicios es una ligera variación en la inyección de dependencia. En lugar de dar un objeto que pueda usar, le pasa un objeto que sabe cómo ubicar (crear) el objeto que desea usar.
class Application
{
public:
Application(Persister& p)
: persistor(p)
{}
void save()
{
std::auto_ptr<SaveDialog> saveDialog = persistor.getSaveDialog();
saveDialog.DoSaveAction();
}
void load()
{
std::auto_ptr<LoadDialog> loadDialog = persistor.getLoadDialog();
loadDialog.DoLoadAction();
}
private:
Persister& persistor;
};
Aquí pasamos el objeto de aplicación un objeto persistente. Cuando realiza una acción de guardar / cargar, utiliza el persistor para crear un objeto que realmente sabe cómo realizar la acción. Nota: Una vez más, el persistor es una interfaz y puede proporcionar diferentes implementaciones según la situación.
Esto es útil cuando potentially
se requiere un objeto único cada vez que crea una instancia de una acción.
Personalmente, creo que esto es particularmente útil para escribir pruebas unitarias.
Nota de patrones:
Los patrones de diseño son un tema enorme en sí mismo. De ninguna manera es una lista exclusiva de patrones que puede usar para ayudar con el acoplamiento suelto; Este es solo un punto de partida común.
Con experiencia, se dará cuenta de que ya está usando estos patrones, es solo que no usó sus nombres formales. Al estandarizar sus nombres (y hacer que todos los aprendan) descubrimos que es más fácil y rápido comunicar ideas.