Respostas:
Acoplamento apertado é quando um grupo de classes é altamente dependente um do outro.
Esse cenário surge quando uma classe assume muitas responsabilidades ou quando uma preocupação é espalhada por muitas classes em vez de ter sua própria classe.
O acoplamento frouxo é alcançado por meio de um design que promove responsabilidade única e separação de preocupações.
Uma classe fracamente acoplada pode ser consumida e testada independentemente de outras classes (concretas).
As interfaces são uma ferramenta poderosa a ser usada para dissociar. As classes podem se comunicar por meio de interfaces, em vez de outras classes concretas, e qualquer classe pode estar do outro lado dessa comunicação simplesmente implementando a interface.
Exemplo de acoplamento apertado:
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)
{
}
}
Exemplo de acoplamento solto:
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)
{
}
}
Outro exemplo aqui .
O chapéu é "fracamente acoplado" ao corpo. Isso significa que você pode tirar o chapéu facilmente sem fazer alterações na pessoa / corpo. Quando você pode fazer isso, então você tem "acoplamento solto". Veja abaixo a elaboração.
Pense na sua pele. Está preso ao seu corpo. Se encaixa como uma luva. Mas e se você quisesse mudar a cor da sua pele de branca para verde? Você pode imaginar o quão doloroso seria descascar sua pele, tingi-la e colá-la novamente etc? Mudar a pele é difícil porque está fortemente acoplado ao seu corpo. Você simplesmente não pode fazer alterações facilmente. Você teria que redesenhar fundamentalmente um ser humano para tornar isso possível.
Deus não era um bom programador orientado a objetos.
Agora pense em se vestir de manhã. Você não gosta de azul? Sem problemas: você pode vestir uma camisa vermelha. Você pode fazer isso com facilidade e sem esforço, porque a camiseta não está realmente conectada ao seu corpo da mesma maneira que a sua pele. A camiseta não sabe nem se importa com o corpo . Em outras palavras, você pode trocar de roupa sem realmente mudar seu corpo.
Esse é o conceito básico em poucas palavras.
É importante porque o software muda o tempo todo. De um modo geral, você deseja modificar facilmente seu código, sem alterá-lo. Eu sei que isso soa como um oxímoro, mas por favor, tenha paciência comigo.
Exemplos de CSV / JSON / DB: se alguém deseja sua saída em um arquivo CSV, em vez de JSON etc., ou se você deseja mudar do MySQL para PostGreSQL, poderá fazer essas alterações com extrema facilidade no seu código, sem precisar reescrever a classe inteira etc. Em outras palavras, você não deseja associar firmemente seu aplicativo a uma implementação de banco de dados específica (por exemplo, Mysql) ou a uma saída específica (por exemplo, arquivos CSV). Porque, como é inevitável no software, as mudanças virão. Quando eles chegam, é muito mais fácil se as partes do seu código estão fracamente acopladas.
Exemplo de peças para carros: se alguém quiser o carro em preto , não será necessário reprojetar o carro inteiro para fazer isso. Um carro e suas peças de reposição seriam um exemplo perfeito de uma arquitetura fracamente acoplada. Se você deseja substituir o seu motor por um melhor, você pode simplesmente remover o seu motor sem muito esforço e trocá-lo por um melhor. Se o seu carro funcionar apenas com os motores Rolls Royce 1234 e sem outros motores - o seu carro estará fortemente acoplado a esse motor (Rolls Royce 1234). Seria melhor se você alterasse o design do seu carro para que ele funcionasse com qualquermotor, para que seja um pouco mais frouxamente acoplado aos seus componentes. Melhor ainda seria se o seu carro pudesse funcionar sem a necessidade de um motor! Alguma quantidade de acoplamento vai acontecer, mas você deve trabalhar para minimizá-lo o máximo possível. Por quê? Porque quando os requisitos mudam, ainda devemos poder fornecer software de boa qualidade, muito rapidamente e somos auxiliados nesse objetivo por acoplamentos soltos.
Em resumo, o acoplamento flexível facilita a alteração do código. As respostas acima fornecem algum código que vale a pena ler neste momento.
Re: Comentários do @TimoHuovinen - o conceito de acoplamento solto anda de mãos dadas com os conceitos de polimorfismo. Se você entender a analogia básica das peças de uma camisa / carro, estará pronto para entender o polimorfismo. A melhor maneira, neste momento, é ler os exemplos de código fornecidos por meus colegas estimados nas outras respostas deste tópico. Se eu disser mais, você pode ficar sobrecarregado com muitas informações.
No design orientado a objetos, a quantidade de acoplamento refere-se a quanto o design de uma classe depende do design de outra classe. Em outras palavras, com que frequência as alterações na classe A forçam alterações na classe B? Um acoplamento apertado significa que as duas classes geralmente mudam juntas; um acoplamento solto significa que na maior parte são independentes. Em geral, o acoplamento solto é recomendado porque é mais fácil testar e manter.
Você pode encontrar este documento de Martin Fowler (PDF) útil.
Em geral, o Tight Coupling é ruim, mas na maioria das vezes, porque reduz a flexibilidade e a reutilização do código, torna as alterações muito mais difíceis, impede a testabilidade etc.
Objeto firmemente acoplado é um objeto que precisa conhecer um pouco um do outro e geralmente é altamente dependente uma da outra interface. Alterar um objeto em um aplicativo fortemente acoplado geralmente requer alterações em vários outros objetos. Em aplicativos pequenos, podemos identificar facilmente as alterações e há menos chances de perder qualquer coisa. Mas, em grandes aplicações, essas interdependências nem sempre são conhecidas por todos os programadores ou existem chances de perder alterações. Mas cada conjunto de objetos fracamente acoplados não depende de outros.
Em resumo, podemos dizer que o acoplamento frouxo é uma meta de projeto que busca reduzir as interdependências entre os componentes de um sistema com a meta de reduzir o risco de que alterações em um componente exijam alterações em qualquer outro componente. O acoplamento flexível é um conceito muito mais genérico, destinado a aumentar a flexibilidade de um sistema, torná-lo mais sustentável e tornar a estrutura inteira mais 'estável'.
Acoplamento refere-se ao grau de conhecimento direto que um elemento possui de outro. podemos dizer um exemplo: A e B, somente B muda seu comportamento somente quando A muda seu comportamento. Um sistema fracamente acoplado pode ser facilmente dividido em elementos definíveis.
Quando dois objetos são fracamente acoplados, eles podem interagir, mas têm muito pouco conhecimento um do outro.
Projetos fracamente acoplados nos permitem construir sistemas OO flexíveis que podem lidar com mudanças.
O padrão de design do observador é um bom exemplo para criar classes pouco acopladas. Você pode dar uma olhada na Wikipedia .
Um extrato da minha postagem no blog sobre acoplamento:
O que é acoplamento estanque : -
Como definição acima, um Objeto firmemente acoplado é um objeto que precisa conhecer outros objetos e, geralmente, é altamente dependente das interfaces um do outro.
Quando alteramos um objeto em um aplicativo fortemente acoplado, geralmente é necessário alterar vários outros objetos. Não há problema em um aplicativo pequeno, podemos identificar facilmente a alteração. Porém, no caso de aplicativos grandes, essas interdependências nem sempre são conhecidas por todos os consumidores ou outros desenvolvedores ou há muitas chances de mudanças futuras.
Vamos dar um código de demonstração do carrinho de compras para entender o acoplamento rígido:
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 com o exemplo acima
O acoplamento apertado cria algumas dificuldades.
Aqui, OrderTotal()
métodos é o valor total para os itens atuais dos carrinhos. Se quisermos adicionar os recursos de desconto neste sistema de carrinho. É muito difícil fazer isso no código acima, porque precisamos fazer alterações em todas as classes, pois ele é muito bem acoplado.
Um acoplamento fraco significa que o grau de dependência entre dois componentes é muito baixo.
Exemplo: GSM SIM
Um acoplamento rígido significa que o grau de dependência entre dois componentes é muito alto.
Exemplo: CDMA Mobile
Pelo que entendi, a arquitetura fortemente acoplada não oferece muita flexibilidade para mudanças quando comparada à arquitetura pouco acoplada.
Porém, no caso de arquiteturas fracamente acopladas, formatos de mensagem ou plataformas operacionais ou reformulação da lógica de negócios, isso não afeta a outra extremidade. Se o sistema for desativado para uma revisão, é claro que a outra extremidade não poderá acessar o serviço por um tempo, mas, além disso, a extremidade inalterada poderá retomar a troca de mensagens como era antes da revisão.
Acoplamento apertado significa que uma classe depende de outra classe.
Loose Coupling significa que uma classe depende da interface e não da classe.
No acoplamento rígido , há uma dependência codificada declarada nos métodos.
No acoplamento flexível , devemos passar a dependência externamente no tempo de execução, em vez de codificados. (Os sistemas de pares soltos usam a interface para diminuir a dependência da classe.)
Por exemplo, temos um sistema que pode enviar saída de duas ou mais maneiras, como saída JSON, saída 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();
}
}
No exemplo acima, se queremos alterar a saída em JSON, precisamos localizar e alterar todo o código, porque a Class1 está fortemente acoplada à classe 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();
}
}
Existem certas ferramentas que fornecem injeção de dependência por meio de sua biblioteca, por exemplo, em .net, nós injetamos a biblioteca .
Se você estiver indo mais longe em java, o spring fornece esses recursos.
Objetos fracamente acoplados podem ser criados introduzindo interfaces no seu código, é o que essas fontes fazem.
Diga no seu código que você está escrevendo
Myclass m = new Myclass();
agora essa declaração no seu método diz que você é dependente myclass
disso e é chamada de fortemente acoplada. Agora, como você fornece alguma injeção de construtor ou objeto de instanciação e injeção de propriedade, ele se torna fracamente acoplado.
Há muitas respostas legais aqui usando analogias, mas um amigo no trabalho me deu um exemplo que eu gostei mais do que todos os mencionados aqui ... Olhos e óculos!
Acoplamento apertado
Acoplamento apertado seriam os olhos. Se eu quiser corrigir minha visão, é muito caro fazer um transplante de olho e possui uma quantidade razoável de riscos. Mas e se o designer (sendo a raça humana) encontrasse um caminho melhor. Adicione um recurso que esteja fracamente acoplado ao corpo para que ele possa ser facilmente alterado! (sim .. óculos)
Acoplamento solto
Posso substituir facilmente meus óculos sem interromper minha visão subjacente. Posso tirar os óculos e minha visão será como era antes (nem melhor nem pior). O uso de diferentes pares de óculos muda a forma como vemos o mundo através de nossos olhos, com pouco risco e facilidade de manutenção.
Resumo
Então, da próxima vez que alguém lhe perguntar "quem se importa se meu código estiver fortemente associado?" A resposta é sobre esforço para mudar, esforço para manter e risco de mudança.
Então, como isso é feito em c #? Interfaces e injeção de dependência!
EDITAR
Este também é um bom exemplo do padrão Decorator, onde os olhos são da classe que estamos decorando, atendendo aos requisitos da interface, mas oferecendo funcionalidades diferentes (por exemplo, óculos de sol, óculos de leitura, lupas para joalheiro etc.)
O acoplamento flexível é uma resposta a dependências codificadas no estilo antigo e a problemas relacionados a questões como recompilação frequente quando algo muda e a reutilização de código. Ele enfatiza a implementação da lógica de trabalho em componentes e a evitação de códigos de conexão específicos da solução.
Acoplamento solto = IoC Veja isso para obter uma explicação mais fácil.
Loose Coupling é o processo de fornecer a dependência que sua classe precisa indiretamente, sem fornecer todas as informações da dependência (por exemplo, na interface), no caso de um acoplamento rígido que você fornece diretamente na dependência, o que não é uma boa maneira de codificar.
É sobre a taxa de dependência de classes para outras que são tão baixas em acoplamentos frouxos e tão altas em acoplamentos estreitos. Para ficar claro na arquitetura de orientação ao serviço , os serviços são fracamente acoplados uns aos outros contra monolítico que classes de dependência entre si têm um propósito
Se a criação / existência de um objeto depende de outro objeto que não pode ser adaptado, seu acoplamento rígido. E, se a dependência puder ser adaptada, seu acoplamento frouxo. Considere um exemplo em Java:
class Car {
private Engine engine = new Engine( "X_COMPANY" ); // this car is being created with "X_COMPANY" engine
// Other parts
public Car() {
// implemenation
}
}
O cliente da Car
classe pode criar um com o mecanismo ONLY "X_COMPANY".
Considere quebrar esse acoplamento com a capacidade de alterar isso:
class Car {
private Engine engine;
// Other members
public Car( Engine engine ) { // this car can be created with any Engine type
this.engine = engine;
}
}
Agora, a Car
não depende de um mecanismo de "X_COMPANY", pois pode ser criado com tipos.
Uma observação específica de Java: o uso de interfaces Java apenas para desconectar o acoplamento não é uma abordagem apropriada. Em Java, uma interface tem um propósito - agir como um contrato que fornece intrisicamente comportamento / vantagem de desacoplamento.
O comentário de Bill Rosmus na resposta aceita tem uma boa explicação.
Um acoplamento rígido significa que classes e objetos são dependentes um do outro. Em geral, o acoplamento rígido geralmente não é bom porque reduz a flexibilidade e a reutilização do código, enquanto o acoplamento flexível significa reduzir as dependências de uma classe que usa diretamente a classe diferente.
Acoplamento apertado O objeto fortemente acoplado é um objeto que precisa conhecer outros objetos e geralmente é altamente dependente das interfaces um do outro. A alteração de um objeto em um aplicativo fortemente associado geralmente requer alterações em vários outros objetos. Nas pequenas aplicações, podemos identificar facilmente as alterações e há menos chances de perder alguma coisa. Porém, em aplicativos grandes, essas interdependências nem sempre são conhecidas por todos os programadores e há uma chance de ignorar as alterações. Exemplo:
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());
}
}
No exemplo acima, o código definido por esse tipo de implementação usa acoplamento flexível e é recomendado, pois a classe B precisa passar pela classe A para obter seu estado em que as regras são aplicadas. Se a classe A for alterada internamente, a classe B não será interrompida, pois usa apenas a classe A como meio de comunicação.
Output
getA() method
aObject value is: 0