Respuestas:
El acoplamiento apretado es cuando un grupo de clases depende mucho el uno del otro.
Este escenario surge cuando una clase asume demasiadas responsabilidades, o cuando una preocupación se extiende a muchas clases en lugar de tener su propia clase.
El acoplamiento flojo se logra mediante un diseño que promueve la responsabilidad individual y la separación de preocupaciones.
Una clase débilmente acoplada puede consumirse y probarse independientemente de otras clases (concretas).
Las interfaces son una herramienta poderosa para usar para desacoplar. Las clases pueden comunicarse a través de interfaces en lugar de otras clases concretas, y cualquier clase puede estar en el otro extremo de esa comunicación simplemente implementando la interfaz.
Ejemplo de acoplamiento apretado:
class CustomerRepository
{
private readonly Database database;
public CustomerRepository(Database database)
{
this.database = database;
}
public void Add(string CustomerName)
{
database.AddRow("Customer", CustomerName);
}
}
class Database
{
public void AddRow(string Table, string Value)
{
}
}
Ejemplo de acoplamiento flojo:
class CustomerRepository
{
private readonly IDatabase database;
public CustomerRepository(IDatabase database)
{
this.database = database;
}
public void Add(string CustomerName)
{
database.AddRow("Customer", CustomerName);
}
}
interface IDatabase
{
void AddRow(string Table, string Value);
}
class Database implements IDatabase
{
public void AddRow(string Table, string Value)
{
}
}
Otro ejemplo aquí .
El sombrero está "débilmente acoplado" al cuerpo. Esto significa que puede quitarse fácilmente el sombrero sin hacer ningún cambio en la persona / cuerpo. Cuando puedes hacer eso, entonces tienes "acoplamiento flojo". Ver abajo para más detalles.
Piensa en tu piel. Está pegado a tu cuerpo. Se ajusta como un guante. Pero, ¿y si quisieras cambiar el color de tu piel de blanco a verde? ¿Te imaginas lo doloroso que sería despegar tu piel, teñirla y luego pegarla de nuevo, etc.? Cambiar su piel es difícil porque está estrechamente acoplado a su cuerpo. Simplemente no puedes hacer cambios fácilmente. Tendría que rediseñar fundamentalmente a un ser humano para que esto sea posible.
Dios no era un buen programador orientado a objetos.
Ahora piensa en vestirte por la mañana. ¿No te gusta el azul? No hay problemas: puedes ponerte una camisa roja. Puede hacerlo fácilmente y sin esfuerzo porque la camisa no está realmente conectada a su cuerpo de la misma manera que su piel. La camisa no sabe ni le importa de qué cuerpo se trata . En otras palabras, puedes cambiarte de ropa, sin cambiar realmente tu cuerpo.
Ese es el concepto básico en pocas palabras.
Es importante porque el software cambia todo el tiempo. En términos generales, desea poder modificar fácilmente su código, sin cambiar su código. Sé que suena como un oxímoron, pero por favor tengan paciencia conmigo.
Ejemplos de CSV / JSON / DB: si alguien quiere su salida en un archivo CSV en lugar de JSON, etc., o si desea cambiar de MySQL a PostGreSQL, debería poder hacer esos cambios extremadamente fácilmente en su código, sin tener que volver a escribir toda la clase, etc. En otras palabras, no desea acoplar estrechamente su aplicación con una implementación de base de datos específica (por ejemplo, Mysql) o con una salida particular (por ejemplo, archivos CSV). Porque, como es inevitable en el software, vendrán cambios. Cuando llegan, es mucho más fácil si sus partes de su código están unidas libremente.
Ejemplo de piezas de automóviles: si alguien quiere su automóvil en negro , no debería tener que rediseñar todo el automóvil para hacerlo. Un automóvil y sus repuestos serían un ejemplo perfecto de una arquitectura débilmente acoplada. Si desea reemplazar su motor por uno mejor, debería poder simplemente quitar su motor sin demasiado esfuerzo y cambiarlo por uno mejor. Si su automóvil solo funciona con motores Rolls Royce 1234 y ningún otro motor, entonces su automóvil estará estrechamente acoplado a ese motor (Rolls Royce 1234). Sería mejor si cambiara el diseño de su automóvil para que funcione con cualquiermotor, para que esté un poco más flojo junto con sus componentes. ¡Aún mejor sería si su automóvil pudiera funcionar sin necesidad de un motor! Va a ocurrir una cierta cantidad de acoplamiento, pero debe trabajar para minimizarlo tanto como sea posible. ¿Por qué? Porque cuando los requisitos cambian, aún deberíamos poder entregar software de buena calidad, muy rápidamente y nos ayuda en ese objetivo mediante un acoplamiento flexible.
En resumen, el acoplamiento suelto hace que el código sea más fácil de cambiar. Las respuestas anteriores proporcionan un código que vale la pena leer en este momento.
Re: @TimoHuovinen comenta: el concepto de acoplamiento suelto va de la mano con los conceptos de polimorfismo. Si comprende la analogía básica de una camisa / autopartes, entonces estará listo para darle sentido al polimorfismo. La mejor manera, en este punto, es leer las muestras de código proporcionadas por mis estimados colegas en las otras respuestas en este hilo. Si digo algo más, puede que te sobrecargues con demasiada información.
En el diseño orientado a objetos, la cantidad de acoplamiento se refiere a cuánto depende el diseño de una clase del diseño de otra clase. En otras palabras, ¿con qué frecuencia los cambios en la clase A fuerzan los cambios relacionados en la clase B? El acoplamiento apretado significa que las dos clases a menudo cambian juntas, el acoplamiento flojo significa que son en su mayoría independientes. En general, se recomienda un acoplamiento flojo porque es más fácil de probar y mantener.
Puede encontrar útil este documento de Martin Fowler (PDF) .
En general, el acoplamiento apretado es malo, pero la mayoría de las veces, porque reduce la flexibilidad y la reutilización del código, hace que los cambios sean mucho más difíciles, impide la capacidad de prueba, etc.
El objeto estrechamente acoplado es un objeto que necesita saber bastante el uno del otro y, por lo general, depende mucho de las interfaces entre sí. Cambiar un objeto en una aplicación estrechamente acoplada a menudo requiere cambios en varios otros objetos. En una aplicación pequeña, podemos identificar fácilmente los cambios y hay menos posibilidades de perder algo. Pero en las aplicaciones grandes, no todos los programadores conocen siempre estas interdependencias o existe la posibilidad de perder los cambios. Pero cada conjunto de objetos débilmente acoplados no depende de otros.
En resumen, podemos decir que el acoplamiento flexible es un objetivo de diseño que busca reducir las interdependencias entre los componentes de un sistema con el objetivo de reducir el riesgo de que los cambios en un componente requieran cambios en cualquier otro componente. El acoplamiento flexible es un concepto mucho más genérico destinado a aumentar la flexibilidad de un sistema, hacerlo más fácil de mantener y hacer que todo el marco sea más 'estable'.
El acoplamiento se refiere al grado de conocimiento directo que un elemento tiene de otro. podemos decir, por ejemplo: A y B, solo B cambia su comportamiento solo cuando A cambia su comportamiento. Un sistema débilmente acoplado puede descomponerse fácilmente en elementos definibles.
Cuando dos objetos están débilmente acoplados, pueden interactuar pero tienen muy poco conocimiento el uno del otro.
Los diseños poco acoplados nos permiten construir sistemas OO flexibles que pueden manejar el cambio.
El patrón de diseño del observador es un buen ejemplo para hacer que las clases se acoplen libremente, puedes echarle un vistazo en Wikipedia .
Un extracto de mi publicación de blog sobre el acoplamiento:
¿Qué es el acoplamiento apretado ?
Como en la definición anterior, un objeto estrechamente acoplado es un objeto que necesita saber acerca de otros objetos y generalmente depende en gran medida de las interfaces de cada uno.
Cuando cambiamos un objeto en una aplicación estrechamente acoplada, a menudo requiere cambios en varios otros objetos. No hay problema en una pequeña aplicación, podemos identificar fácilmente el cambio. Pero en el caso de aplicaciones grandes, estas interdependencias no siempre son conocidas por todos los consumidores u otros desarrolladores o hay muchas posibilidades de cambios futuros.
Tomemos un código de demostración del carrito de compras para comprender el acoplamiento estrecho:
namespace DNSLooseCoupling
{
public class ShoppingCart
{
public float Price;
public int Quantity;
public float GetRowItemTotal()
{
return Price * Quantity;
}
}
public class ShoppingCartContents
{
public ShoppingCart[] items;
public float GetCartItemsTotal()
{
float cartTotal = 0;
foreach (ShoppingCart item in items)
{
cartTotal += item.GetRowItemTotal();
}
return cartTotal;
}
}
public class Order
{
private ShoppingCartContents cart;
private float salesTax;
public Order(ShoppingCartContents cart, float salesTax)
{
this.cart = cart;
this.salesTax = salesTax;
}
public float OrderTotal()
{
return cart.GetCartItemsTotal() * (2.0f + salesTax);
}
}
}
Problemas con el ejemplo anterior
El acoplamiento apretado crea algunas dificultades.
Aquí, los OrderTotal()
métodos nos dan la cantidad completa de los artículos actuales de los carros. Si queremos agregar las características de descuento en este sistema de carrito. Es muy difícil de hacer en el código anterior porque tenemos que hacer cambios en cada clase ya que está muy estrechamente acoplado.
El acoplamiento flojo significa que el grado de dependencia entre dos componentes es muy bajo.
Ejemplo: SIM GSM
El acoplamiento apretado significa que el grado de dependencia entre dos componentes es muy alto.
Ejemplo: CDMA Mobile
Según tengo entendido, la arquitectura estrechamente acoplada no proporciona mucha flexibilidad para el cambio en comparación con la arquitectura débilmente acoplada.
Pero en el caso de arquitecturas poco acopladas, formatos de mensajes o plataformas operativas o la renovación de la lógica empresarial no afecta al otro extremo. Si el sistema se retira para una renovación, por supuesto, el otro extremo no podrá acceder al servicio por un tiempo, pero aparte de eso, el extremo sin cambios puede reanudar el intercambio de mensajes como era antes de la renovación.
Acoplamiento ajustado significa que una clase depende de otra clase.
Bajo acoplamiento significa que una clase depende de la interfaz en lugar de la clase.
En el acoplamiento estrecho , hay una dependencia codificada declarada en los métodos.
En acoplamiento flojo , debemos pasar la dependencia externamente en tiempo de ejecución en lugar de codificada. (Los sistemas de pareja suelta usan la interfaz para disminuir la dependencia con la clase).
Por ejemplo, tenemos un sistema que puede enviar resultados de dos o más formas, como salida JSON, salida CSV, etc.
public interface OutputGenerator {
public void generateOutput();
}
public class CSVOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("CSV Output Generator");
}
}
public class JSONOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("JSON Output Generator");
}
}
// In Other Code, we write Output Generator like...
public class Class1 {
public void generateOutput() {
// Here Output will be in CSV-Format, because of hard-coded code.
// This method tightly coupled with CSVOutputGenerator class, if we want another Output, we must change this method.
// Any method, that calls Class1's generateOutput will return CSVOutput, because Class1 is tight couple with CSVOutputGenerator.
OutputGenerator outputGenerator = new CSVOutputGenerator();
output.generateOutput();
}
}
En el ejemplo anterior, si queremos cambiar la salida en JSON, entonces necesitamos encontrar y cambiar todo el código, porque Class1 está estrechamente acoplado con la clase CSVOutputGenerator.
public interface OutputGenerator {
public void generateOutput();
}
public class CSVOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("CSV Output Generator");
}
}
public class JSONOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("JSON Output Generator");
}
}
// In Other Code, we write Output Generator like...
public class Class1 {
public void generateOutput(OutputGenerator outputGenerator) {
// if you want to write JSON, pass object of JSONOutputGenerator (Dependency will be passed externally to this method)
// if you want to write CSV, pass object of CSVOutputGenerator (Dependency will be passed externally to this method)
// Due to loose couple with class, we don't need to change code of Class1, because Class1 is loose coupled with CSVOutputGenerator or JSONOutputGenerator class
// Any method, that calls Class1's generateOutput will desired output, because Class1 does not tight couple with CSVOutputGenerator or JSONOutputGenerator class
OutputGenerator outputGenerator = outputGenerator;
output.generateOutput();
}
}
Existen ciertas herramientas que proporcionan inyección de dependencia a través de su biblioteca, por ejemplo, en .net tenemos ninject Library .
Si va más allá en Java, entonces la primavera proporciona estas capacidades.
Los objetos poco acoplados pueden hacerse introduciendo interfaces en su código, eso es lo que hacen estas fuentes.
Di en tu código que estás escribiendo
Myclass m = new Myclass();
ahora esta declaración en su método dice que usted depende de myclass
esto se llama estrechamente acoplado. Ahora proporciona una inyección de constructor, o una inyección de propiedad y un objeto de instanciación, entonces se acoplará libremente.
Aquí hay muchas respuestas agradables usando analogías, pero un amigo en el trabajo me dio un ejemplo que me gustó más que todos los mencionados aquí ... ¡Ojos y gafas!
Acoplamiento apretado
Un acoplamiento apretado serían los ojos. Si quiero arreglar mi visión, es muy costoso recibir un trasplante de ojo y conlleva un riesgo considerable. Pero, ¿qué pasaría si el diseñador (siendo la raza humana) encontrara una mejor manera? ¡Agregue una función que esté acoplada sin apretar al cuerpo para que se pueda cambiar fácilmente! (si .. gafas)
Bajo acoplamiento
Puedo reemplazar mis lentes fácilmente sin romper mi visión subyacente. Puedo quitarme las gafas y mi visión será como era antes (ni mejor ni peor). El uso de diferentes pares de anteojos cambia la forma en que vemos el mundo a través de nuestros ojos con poco riesgo y fácil mantenimiento.
Resumen
Entonces, la próxima vez que alguien le pregunte "¿a quién le importa si mi código está estrechamente acoplado?" La respuesta tiene que ver con el esfuerzo por cambiar, el esfuerzo por mantener y el riesgo de cambio.
Entonces, ¿cómo se hace esto en C #? ¡Interfaces e inyección de dependencias!
EDITAR
Este también es un buen ejemplo del patrón Decorador, donde los ojos son la clase que estamos decorando al cumplir con los requisitos de la interfaz, pero brindando una funcionalidad diferente (por ejemplo, gafas de sol, gafas de lectura, lupas para joyeros, etc.)
El acoplamiento flojo es una respuesta a las dependencias codificadas de estilo antiguo y problemas relacionados, como la recompilación frecuente cuando algo cambia y la reutilización del código. Hace hincapié en implementar la lógica del trabajador en los componentes y evitar el código de conexión específico de la solución allí.
Acoplamiento suelto = IoC Vea esto para una explicación más fácil.
El acoplamiento flojo es el proceso de proporcionar la dependencia que su clase necesita indirectamente sin proporcionar toda la información de la dependencia (es decir, desde la interfaz) en caso de que el acoplamiento estrecho que proporcione directamente en la dependencia no sea una buena forma de codificación.
Se trata de la tasa de dependencia de clases a otras que es tan baja en acoplamientos sueltos y tan alta en acoplamientos ajustados. Para que quede claro en la arquitectura de orientación del servicio , los servicios se acoplan libremente entre sí contra el monolítico, qué clases de dependencia entre sí es a propósito
Si la creación / existencia de un objeto depende de otro objeto que no se puede adaptar, es un acoplamiento estrecho. Y, si la dependencia se puede adaptar, su acoplamiento flojo. Considere un ejemplo en Java:
class Car {
private Engine engine = new Engine( "X_COMPANY" ); // this car is being created with "X_COMPANY" engine
// Other parts
public Car() {
// implemenation
}
}
El cliente de Car
clase puede crear uno con SOLO motor "X_COMPANY".
Considere romper este acoplamiento con la capacidad de cambiar eso:
class Car {
private Engine engine;
// Other members
public Car( Engine engine ) { // this car can be created with any Engine type
this.engine = engine;
}
}
Ahora, a Car
no depende de un motor de "X_COMPANY", ya que se puede crear con tipos.
Una nota específica de Java: el uso de interfaces Java solo para desacoplar no es un enfoque de diseño adecuado. En Java, una interfaz tiene un propósito: actuar como un contrato que proporciona intrínsecamente un comportamiento / ventaja de desacoplamiento.
El comentario de Bill Rosmus en respuesta aceptada tiene una buena explicación.
El acoplamiento apretado significa que las clases y los objetos dependen unos de otros. En general, el acoplamiento estrecho generalmente no es bueno porque reduce la flexibilidad y la reutilización del código, mientras que el acoplamiento flojo significa reducir las dependencias de una clase que usa la clase diferente directamente.
Acoplamiento ajustado El objeto estrechamente acoplado es un objeto que necesita saber acerca de otros objetos y generalmente depende en gran medida de las interfaces de cada uno. Cambiar un objeto en una aplicación estrechamente acoplada a menudo requiere cambios en varios otros objetos. En las aplicaciones pequeñas, podemos identificar fácilmente los cambios y hay menos posibilidades de perder algo. Pero en aplicaciones grandes, estas interdependencias no siempre son conocidas por todos los programadores y existe la posibilidad de pasar por alto los cambios. Ejemplo:
class A {
public int a = 0;
public int getA() {
System.out.println("getA() method");
return a;
}
public void setA(int aa) {
if(!(aa > 10))
a = aa;
}
}
public class B {
public static void main(String[] args) {
A aObject = new A();
aObject.a = 100; // Not suppose to happen as defined by class A, this causes tight coupling.
System.out.println("aObject.a value is: " + aObject.a);
}
}
In the above example, the code that is defined by this kind of implementation uses tight coupling and is very bad since class B knows about the detail of class A, if class A changes the variable 'a' to private then class B breaks, also class A's implementation states that variable 'a' should not be more than 10 but as we can see there is no way to enforce such a rule as we can go directly to the variable and change its state to whatever value we decide.
Output
aObject.a value is: 100
Loose Coupling
Loose coupling is a design goal to reduce the inter-dependencies between components of a system with the goal of reducing the risk that changes in one component will require changes in any other component.
Loose coupling is a much more generic concept intended to increase the flexibility of the system, make it more maintainable and makes the entire framework more stable.
Example:
class A {
private int a = 0;
public int getA() {
System.out.println("getA() method");
return a;
}
public void setA(int aa) {
if(!(aa > 10))
a = aa;
}
}
public class B {
public static void main(String[] args) {
A aObject = new A();
aObject.setA(100); // No way to set 'a' to such value as this method call will
// fail due to its enforced rule.
System.out.println("aObject value is: " + aObject.getA());
}
}
En el ejemplo anterior, el código que se define mediante este tipo de implementación utiliza un acoplamiento flexible y se recomienda ya que la clase B tiene que pasar por la clase A para obtener su estado donde se aplican las reglas. Si la clase A se cambia internamente, la clase B no se romperá, ya que usa solo la clase A como una forma de comunicación.
Output
getA() method
aObject value is: 0