Related
This is one of a number of things that's been bugging me for a while and for which quibbling over the correct interpretation of this has been leading me in a number of attempted coding projects to more fussing around with design, than it has with making steady forward progress, because I want to make sure I've gotten it "right".
In this case, I have a question about the "interface segregation principle" (ISP) of the five "SOLID" principles of basic object oriented design. Its "canonical" statement is this:
Clients should not be forced to depend on methods they do not use.
However, the question here is, is what is the "client" - because this leads to very different interpretations, and also leads to a seeming dilemma when applied in practice, which is what I'd like to understand if first actually is one, and second, how to best solve it.
One interpretation of this is that it is a "single responsibility principle" for interfaces instead of just classes: i.e. if you have an interface IMessageReceiver, it better not include a Send method. Another possible interpretation is that it means that the implementer of an interface should not be required to implement empty methods, while a third interpretation is that the caller should not be able to see any more methods than it actually needs. And the thing is, I can see merit in all three of these interpretations, yet when you apply them all, it seems that in any suitably large project, highly counterintuitive and seemingly problematic things result. In particular, it's that third one that seems to be the rub.
For one, if something gets used in enough places, it is particularly that last one - the "caller" one - which generally tends to "bite" in that it results naturally in your interfaces being atomized down to single methods only. For example, consider a simple interface to a backend storage or database, which may have a load, save, and update method. Some callers of that, though, may not want to save anything. They may just want to peek at the data. Hence to avoid violating the caller interpretation, we must split off the load method. Add a few more use cases and now it's atomized into a IDataLoader, IDataSaver, and IDataUpdater which all have 1 method each.
And I can't help but feel this almost seems like an anti-pattern, particularly if it happens with enough objects owing to them being used in a suitably wide variety of places. Is it? Or am I misinterpreting something here? After all, nobody makes a generic container class (like the "list", "map", etc. things in a lot of languages) with single-method interfaces to be piecemealed out to whatever it gets passed to.
One interpretation of this is that it is a "single responsibility principle" for interfaces...
Robert Martin has addressed this question directly, and his answer is that ISP separates things that SRP does not, thus the two principles differ.
Another possible interpretation is that it means that the implementer of an interface...
We also see in his answer that the client is the caller of the interface, not the implementer. I've touched on that in another answer regarding default methods. The implementer should be implementing exactly as many methods as the caller needs: no more, no less.
a third interpretation is that the caller should not be able to see any more methods than it actually needs.
This is correct, and it is also correct to note that a single-method interface cannot violate the ISP. While this may result in a "lowest-common-denominator" approach where every interface is a single method, they should be highly composable in that case; i.e. implementations can select several interfaces to implement, making them highly customizable to client needs.
The database example of separating read from write is so common that is has its own pattern: CQRS. There are arguments both ways. Likewise, generic collections may choose to avoid creating too many interfaces, which is a design counter to the ISP.
I would suggest that in most applications (particularly service applications as opposed to libraries) if rigorously applying the ISP results exclusively in single-method interfaces, it indicates the clients are not cohesive and not complex. If this is an accurate description of the clients, then single-method interfaces are probably appropriate. You may also consider a different architecture such as a separate service for each client if their requirements have so little overlap.
When somebody wants to develop a feature, then he/she tries to map real world object to unit where code can be put. It is done to imitate behavior.
This unit can be called class. And this class has to have just one feature. It is place where we use SRP.
E.g., if programmer maps real world object person to class Person.
Then this class Person does not have to have methods/behavior of other objects. E.g. the Person class does not have to have methods of Car class. This is what SRP about.
Clients should not be forced to depend on methods they do not use.
We've created a Person class so far. Now we want to log all speech of person. So we need to log it. How? We can use interface ILogging with one method Log. Why does this interface have just one method?
Because clients will only have to know about the methods that are of interest to them.
Here Person class is client of interface ILogging.
SRP means that a class is responsible just for one feature. E.g. if you want to edit logging in Person class, then it is violation of SRP.
public class Person
{
public string FirstName { get; set; }
public void Say(string message)
{
File.WriteAllText("path", message); // violation of SRP
}
}
How can we avoid violation of SRP? We should create an abstraction of logging:
public interface ILogging
{
void Write(string address, string content);
}
and use it:
public class PersonWithSRP
{
private readonly ILogging _logging;
public string FirstName { get; set; }
public PersonWithSRP(ILogging logging)
{
_logging = logging;
}
public void Say(string message)
{
_logging.Write("path", message);
}
}
public class Logging : ILogging
{
public void Write(string address, string content)
{
File.WriteAllText(address, content);
}
}
By extracting logic of logging in separate class, we moved logic of logging in special, single class or place where we can edit only logic of logging on one place.
What is about ISP?
nobody makes a generic container class
yeah, you are right. Interface should have only necessary methods which client class needs.
An example with HDD that uses ISP:
public interface IReadable
{
string Read();
}
public interface IWriteable
{
void Write();
}
public class HDD : IReadable, IWriteable
{
public string Read() { }
public void Write() { }
}
By creating one interface for Read() and Write() methods, it would obligate class to implement both methods in class. But some classes only want to read data, others want to write data, and some to do both. So in this case it is better to create separate interfaces.
So let's look another example with CardReader. CardReader just reads data, it does not write data. So, if we inherit one interface with Read() and Write() methods, then we would violate ISP principle. An example of violation of ISP:
public interface IWriteReadable
{
string Read();
void Write();
}
public class CardReader : IWriteReadable
{
// this is a necessary method
public string Read() { }
// here we are obligating to implement unnecessary method of interface
public void Write() { }
}
So by applying ISP, you only puts methods in interface that are necessary for the client class. If your class/client just wants to read data, then you need to use IReadable interface, not IReadableWriteable.
Quite a mouth-full of a question but its a OO principle I've struggling with. Lets say i have an e-commerce app and there is the concept of payment method, examples could be CreditCard, Paypal, Apple pay etc. The user has a choice of which payment method to select so i need to present them all in a list on the screen and depending on the selection this will be used to drive a UI, presenting different text/images/interactions as well as will be serialised slightly differently into a Payment request over the wire.
Here is some code:
public class PaypalPayment : PaymentMethod {
public string Token;
public string String;
}
public class CreditCardPayment : PaymentMethod {
public Address Address;
public CreditCard CreditCard;
}
interface PaymentMethod {
}
public class Booking {
public PaymentMethod PaymentMethod; //generic object
//or
public PaypalPayment PaypalPayment;
public CreditCardPayment CreditCardPayment;
}
So in my booking class i can either have a generic payment object referred to by the interface but i cant get to the underlying type without casting which sucks, as in reality them don't share any common properties doman-wise. Alternatively i have multiple properties which feels bad in a different way. The user can only select one payment method so the others will have to null or some kind of null object, i would have to either query an enum or ask each payment method if it is null. Also my payment method select screen is a bit more cumbersome as i cant just iterate on a generic type i have to explicitly build up the list.
In theory i could add some methods to the PaymentMethod interface, such as Serialise() or some UI presentation methods which all the payment methods have in common but then i would have to implement them in my model object which i don't want to do in my model layer.
Overall i dont have a clean solution for this in your typical object orientated language. I wrote this in c# but this could apply to any OO language.
Data seems to have been segregated away from logic in your design. As a consequence, Booking probably has to indulge in Inappropriate Intimacy with its Payment in order for the behavior to take place, hence the casting problem.
An idiomatic OO implementation would 1/ define a clear responsibility and 2/ encapsulate operations and data for it in the same class. Then you can have an abstraction on top of a family of these classes so that their behavior can be called uniformly by consumer code.
The Strategy aka Policy pattern might be a good choice for payment.
UI wise, it may be better to avoid using abstractions and have different UIs altogether for different payment methods. Or, you could have an abstract UI payment model whose concrete implementations know how to render themselves.
To have an interface and can't get to the underlying type is exactly what abstraction and loose coppling is striving for. This should not suck but should be desirable.
To get all possible instances to choose from, you could use a repository that returns a collection of all your payment methods.
To implement this repository you could use your favored ORM and load them from the database, use your favored IoC/DI Container and let it create all implementors of your interface, or hard code the creation. Whatever suits you needs and the needs of the project. If you use an interface for the repository as well, you can later swap the implementation.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I tend to create very large classes that have 30-40 (or more) methods. How many methods are too many? Are there any "smells" or rules of thumb to use?
Step one is to adhere to the Single Responsibility Principle. If you can't say in one sentence what your class does, then it probably does too much.
Once you've narrowed that down, I don't know that the number of methods really matters as long as your methods don't do too much.
I'll bite. Without doing much more than wading into the very shallow edges of the deep waters of O-O design, I'll through a couple of my rules of thumb:
Static properties are highly questionable. Question yourself strongly about whether or not they are really needed.
Most properties/attributes of a class should be private (accessable only by the object instance) or protected, accessable only by an instance of the class or of a derived class (subclass).
If a property/attribute of a class is visible to the general public, it should most likely be read-only. For the most part, the state of an object instance should change only by its responding to a method asking it to do something useful (e.g., you request that a window move itself, rather than explicitly setting is origin on the coordinate plane).
Public Getter/Setter methods or properties are questionable as they primarily expose object state (which see item #2 above).
Public methods should primarily expose the logical operations (messages) to which an object instance responds. These operations should be atomic (e.g., for the object to be in a logically consistent internal state, it should not depend on an external actors sending it a particular sequence of messages). Object state should change are as result of responding to these messages and should be exposed as a side effect of the message (e.g., a window reporting its location as a side effect of asking it to move is acceptable).
The above should cut down the public interface to your objects considerably.
Finally, if your object has more than a few messages to which it responds, you likely have a candidate for refactoring: is it really one monolithic object, or is it an assembly of discrete objects? "More than a few", of course, is a highly subjective (and contextual) number -- I'll throw out 10-12 as a reasonable limit.
Hope this helps.
There are lots of books out there on O-O design, analysis and modelling.
As others have said, a class is too big when it is trying to do more than one thing and violates the Single Responsibility Principle.
An excellent book on this and other topics (and one I strongly recommend for any developer) is Clean Code by Bob Martin.
static classes such as Math are likely to have lots of methods. It would be confusing to split them.
A general guideline for design: if a reasonable person's first reaction to a <set of things> could plausibly be "That's too many <thing>s!", then it's too many <thing>s.
Number of methods by itself is not a reliable indicator. What if 20 of those are just property getters?
Try metrics that are more concrete, though this is always a judgment call. There is a list of 'code smells' here.
It's all relative but check out the single responsibility principle:
In object-oriented programming, the
single responsibility principle states
that every object should have a single
responsibility, and that
responsibility should be entirely
encapsulated by the class
A rule of thumb i've thought of for SRP: Count your usings/imports/includes. If your class has more than half a dozen there's a good chance that you're violating the SRP. But that's a relative idea as well. Certain patterns such as facades will violate this rule out of necessity. E.g. as in simplifying and hiding a complex subsytem.
A point about it is taken in the "Effective C++" 3rd edition:
"Prefer non-member, non-friend functions to member functions". What this means that you should keep your class reasonable small because big classes tend to be difficult to expand (the do not scale well)
You could also check you class for branches. If your class contains may "if's" or "switch'es" there is a high chance that your class responsibility has dissolved. If this is the case refactoring and cutting the responsibilities into smaller parts may lead to smaller classes.
Best Regards,
Marcin
It depends.
If you are in Java with get/set pairs for each field, I'm not surprised. But if each of those methods are 100+ line beasts, that would be a smell.
It depends on whether or not you can split the class in to subclasses.
Edit: What I mean is that you should ask yourself "does this method apply to this class or would it belong to a subclass?"
For example,
Class Animal
- dog_bark()dog_bark() could be moved to a class named Dog, and the method renamed to bark()
There is never a thing as too large of a class, when the PHP interpreter reads your code it compiles into one large executable black of code so splitting them up makes little difference on performance.
BUT:
When it comes down to programming you should never really need 40+ methods in one class, and should be split up into there entites.
Example
class HTTP
{
/*
* Base functions for HTTP Fetching / transferring / Sending
* so when it comes to single responsibility this would be the the fetch / set in HTTP
*/
}
then you would be more specific with your subclasses such as
class YoutubeUploader extends HTTP
{
/*
* This class is responsible for uploading to youtube only
*/
}
class YoutubeDownload extends HTTP
{
/*
* This class is responsible for downloading to youtube only
*/
}
class CronRunner extends HTTP
{
/*
* This class is responsible for Running your HTTP Cron Tasks
*/
}
no if you did not have that BASE HTTP Class you would have to define methods in all three sub classes to transfer data via the HTTP Protocol.
Splitting your classes up unto single responsibilities gives a more structured framework resulting in less code and more outcome.
Everyone ahs already mentioned the: Single Responsibility Principal but its something you should really understand.
There's also ways to reduce code in classes, take this example
class User
{
public function getUsername()
{
return $data['username'];
}
public function getPermissions()
{
return $data['permissions'];
}
public function getFirstname()
{
return $data['firstname'];
}
}
this are not really needed when you can do:
class User
{
public function __call($method,$params = array())
{
if(substr(0,3,$method) == "get")
{
$var_name = substr(3,strlen($method),$method);
return $data[$var_name];
}
}
}
This would take car of any method called that starts with 'get' and it takes the last portion of the string and searches the array.
In general a class should be designed to do one thing and to do it well. Now, with your example of the Math class, it can act as a facade to seperate implementations. Or it can be split up into hierarchy:
public abstract class Math
{
abstract Solve(IMathPayload);
abstract CanSolve(IMathPayload);
}
public class LinearMath : Math {}
public class DifferentialEquasionMath: Math {}
One strategy I like to follow is to create a 'Handle' class for each data model object. Because the handle is responsible for only modification of
that data object, it follows SRP. If I need to create classes outside of data object modification, at least I know most of the code already is SRP compliant.
Q1.
In my university studies of object-oriented modelling and design they recommend thinking about what an object can do for its method, and what its responsibilities are for its attributes. All attempts at clarification have resulted in further confusion.
This tends to generate a class diagram with actors who have all the actions, and inner classes which only hold data.
This doesn't seem correct. Is there another way of thinking about how to model the objects?
Q2. Also, the course seems to emphasize modelling the objects after their real-world counterparts but it doesn't necessarily make sense in the domain model. IE. In a medical practice, they have Patient: CreateAppointment(), CancelAppointment() but that is not how it would be implemented (you would modify a the appointment collection instead). Is there another way of thinking about this?
Example Q1
Secretary: RecordAppointment(), RecordAppointmentCancellation()
Appointment: time, date,... (no methods)
Example Q2
Doctor: SeePatient()
While SeePatient is a use-case, it does not make sense for a method on the actual class. How do you think about this?
Unfortunately, the roadblock you've hit is all too typical in academia. Academic projects tend to start with video rental stores, libraries or student registration systems (yours is a variance of this with a doctor's office) and then inheritance is taught with animals. The guideline you've provided is also very typical
they recommend thinking about what an object can do for its method, and what its responsibilities are for its attributes
In fact when beginners ask I usually explain an object's property's are the things it knows about itself and its methods are the things it knows how to do. Which is really just another way of saying exactly what you have there. As you've discovered this way of thinking quickly breaks down when you start discussing more tangible systems and not just examples.
For instance the guideline works pretty well with this object:
public class Tree
{
public int Height { get; set; }
public void Grow(int byHowMuch)
{
Height += byHowMuch;
}
}
While this certainly fits the bill your right to think that it doesn't "feel" right:
public class Secretary
{
public void MakeAppoinment(Patient patient)
{
//make the appointment
}
}
So what's the solution? It's a matter of taking what you are being taught and applying it. Learning and understanding design patterns will help a lot with developing systems which are more functional than a tree that knows how to grow.
Recommended reading:
Design Patterns: Elements of Reusable Object-Oriented Software (also known as the Gang of Four or GoF)
Head First Design Patterns
Head First Object-Oriented Analysis and Design
To solve the issue you're been presented I would probably use a combination of inherited person classes and interfaces, which would perform their actions through a series of service classes. Essentially a secretary, doctor, and patient would all inherit from person and each of these classes could be passed to accompanying service classes. The service classes may or may not do things like SeePatient(). Please don't take this example to mean that person classes wouldn't have methods.
Stack Overflow has more than a few related questions which may be of use:
Is Single Responsibility Principle a rule of OOP?
Are there any rules for OOP?
why is OOP hard for me?
Additionally, it would be good to check out:
Single responsibility principle
Don't repeat yourself
PrinciplesOfOod
Finally, there isn't a single definition of what makes an application object oriented. How you apply patterns, principles etc. will define your program. The fact that you are asking yourself these questions shows that you are on the right track.
Q1
Is it possible responsibilities of your objects should be interpreted as authorization or contract requirements, as in what actions they should take? So, to take a medical example from your Q2, an object with a Scheduler role (think C#/Java interface, or Obj-C protocol) has attributes around CanEditAppointments or EditsAppointments.
Q2
From a use case perspective, a patient may be able to create an appointment, and so you might implement a Patient in your object model with a method to CreateAppointment(). But, in terms of encapsulation, you would likely instantiate an Appointment object in CreateAppointment(), and then call methods or set properties on the Appointment object to set its time, date, patient, physician, etc.
And because the Appointment collection is likely to be permanent storage like a database, it would likely be the Appointment object's responsibility to add itself to the collection (Appointment.Schedule() goes through your data access layer to save itself to the database).
That also ties back to your Q1, in that the Appointment object's responsibility is to save itself, so it might implement an ISaveAppointment interface that requires fields and methods to carry it out. It also is the Appointment's responsibility to have a date, and time, and patient, etc., before being saved, and so the ISaveAppointment interface should require they exist, and Appointment.Schedule() should validate the values are correct or have been previously validated.
You are right that in many cases there are higher order things which more naturally contain behaviour, like the system, or the user.
You can model this behaviour in classes as static methods which operate on the data model. It isn't OO, but it's fine. You can group related methods together into such classes, and soon you have the notion of "services", as in service oriented programming.
In Java there are specifications and standards for creating such classes, namely the stateless session bean in EJB. The Spring Framework has similar notions with the stereotype "Service" which can be applied to classes to tag them as being facades for business logic.
A service is then a component which encapsulates a certain functionality or behaviour in the system. It operates on a given object model (either its own internal one, or the more general business object model from the system). If you take your use cases and create services which relate directly to them, you can write very maintainable software.
The DCI Architecture is a formalisation of this and an attempt to do the same, but at the same time trying to stay true to object orientation, by adding behaviour to objects as they need it.
I still experience the confusion: "am I telling you to do something else" or "am I doing something someone else asked of me"?
Perhaps all you have to do is play Barbie's, or G.I. Joe's to understand object interaction and where responsibilities go. G.I. Joe got wounded (or Barbie broke a nail) so he calls the Dr's office. "Hey doc, this is Joe, I need an appointment." So you, the kid, tell Barbie to go to the doctor, who needs to know the doc to call and how to call - a reference and public MakeAppointment() method. The Dr. office needs to put the appointment on the books - it's own BookAppointment() method that is the office's procedure for handling appointment requests.
public abstract GenderAppropriateDolly {
protected DrOffice Drkilldare;
public override MakeAppointment() {throw new NotImplementedException();}
}
public class GIJoe : GenderAppropriateDolly {
DrKilldare = new DrOffice();
List<Appointment> myAppointments = new List<Appointment>;
public void MakeAppointment () {
myAppointments.Add(DrKilldare.BookAppointment(this));
}
}
public class DrOffice {
List<Appointment> officeAppointments = new List<Appointments>;
public Appointment BookAppointment(GenderAppropriateDolly forWhom) {
Appointment newappt = new Appointment(formWhom);
this.Appointments.Add(newappt);
return newappt;
}
}
public class Kid {
GenderAppropriateDolly myRoleModel = new GIJoe();
// Joe got wounded so ...
myRoleModel.MakeAppointment();
}
Can any one describe the exact difference between loose coupling and tight coupling in Object oriented paradigm?
Tight coupling is when a group of classes are highly dependent on one another.
This scenario arises when a class assumes too many responsibilities, or when one concern is spread over many classes rather than having its own class.
Loose coupling is achieved by means of a design that promotes single-responsibility and separation of concerns.
A loosely-coupled class can be consumed and tested independently of other (concrete) classes.
Interfaces are a powerful tool to use for decoupling. Classes can communicate through interfaces rather than other concrete classes, and any class can be on the other end of that communication simply by implementing the interface.
Example of tight coupling:
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)
{
}
}
Example of loose coupling:
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)
{
}
}
Another example here.
Explanation without any code
Simple analogy to explain the concept. Code can come later.
Summary Example of Loose Coupling:
In the picture above, the Hat is "loosely coupled" to the body. This means you can easily take the hat off without making any changes to the person/body. When you can do that then you have "loose coupling". See below for elaboration.
Detailed Example
Think of your skin. It's stuck to your body. It fits like a glove. But what if you wanted to change your skin colour from say white to black? Can you imagine just how painful it would be to peel off your skin, dye it, and then to paste it back on etc? Changing your skin is difficult because it is tightly coupled to your body. You just can't make changes easily. You would have to fundamentally redesign a human being in order to make this possible.
Key Point #1: In other words, if you want to change the skin, you would also HAVE TO change the design of your body as well because the two are joined together - they are tightly coupled.
God was not a good object oriented programmer.
Loose coupling (Detailed Example)
Now think of getting dressed in the morning. You don't like blue? No problems: you can put a red shirt on instead. You can do this easily and effortlessly because the shirt is not really connected to your body the same way as your skin. The shirt doesn't know or care about what body it is going on. In other words, you can change your clothes, without really changing your body.
That's key point #2. If you change your shirt, then you are not forced to change your body - when you can do that, then you have loose coupling. When you can't do that, then you have tight coupling.
That's the basic concept in a nutshell.
Why is all of this important?
What do changing shirts have to do with software?
Change. It's inevitable when writing software. If we know in advance that a change is going to come in a particular place, we should loosely couple on that point: then we could make those changes easily and quickly, without bugs.....Consider some examples which might help elaborate:
Loose Coupling in Software:
CSV/JSON Examples: Early on in my career, my manager said: "give me the output as a CSV file". I created a routine that worked like a charm. Then one or two weeks later, he says: "actually, I want the output for another client in JSON".
I had to rewrite the entire thing. But this time, I rewrote it using interfaces - a loosely coupled design pattern. Now, adding new output formats, is so much easier. I can edit the JSON portions without fear I will break my CSV output.
DB Examples: if you want to switch from sqlLite to PostGreSQL easily - loosely coupled code makes it really easy to switch (i.e. to put on a red shirt instead of a blue shirt). The Rails ActiveRecord library is loosely coupled on its database implementation. This makes it super easy for someone to use their own database implementation, while using the same code base!
Cloud Provider examples: Or if you're using AWS and they start charging too much because of market dominance, you should be able to somewhat easily switch to Google or Azure etc. This is precisely the reason why libraries like Active Storage exist - they provide users with a healthy indifference as to the specific cloud provider being used (Azure, AWS S3, GCS etc.). You can easily change cloud providers with just a one-line code change. The implementation details of the cloud storage providers are loosely coupled.
Testing: if you want to test your software, with predetermined outputs and inputs - how are you going to do it? With loosely coupled software - it's a breeze: you can run your tests, and you can also deploy your production code and do it all in the same code base. With tightly coupled code, testing your production code is nearly impossible.
Do we need to make everything "loosely coupled"? Probably not. We should exercise judgement. Some amount of coupling is inevitable. But consider minimizing it if you know in advance where it will change. I would also counsel against guessing where things will change, and loosely coupling everything. Loosely couple, only when you need to.
Summary
In short, loose coupling makes code easier to change.
The answers above provide some code which is worth reading.
Advanced Topics
Loose coupling goes hand-in-hand with polymorphism and interfaces. If you like cartoons and analogies, consider some other posts I have written:
What is Polymorphism?
What is an interface?
What do you mean by 'leaky abstractions' - not written by me.
Picture Attribution.
In object oriented design, the amount of coupling refers to how much the design of one class depends on the design of another class. In other words, how often do changes in class A force related changes in class B? Tight coupling means the two classes often change together, loose coupling means they are mostly independent. In general, loose coupling is recommended because it's easier to test and maintain.
You may find this paper by Martin Fowler (PDF) helpful.
In general Tight Coupling is bad in but most of the time, because it reduces flexibility and re-usability of code, it makes changes much more difficult, it impedes testability etc.
Tightly Coupled Object is an object need to know quite a bit about each other and are usually highly dependent on each other interfaces. Changing one object in a tightly coupled application often requires changes to a number of other objects, In small application we can easily identify the changes and there is less chance to miss anything. But in large applications these inter-dependencies are not always known by every programmer or chance is there to miss changes. But each set of loosely coupled objects are not dependent on others.
In short we can say, loose coupling is a design goal that seeks to reduce the interdependencies 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 a system, make it more maintainable, and make the entire framework more 'stable'.
Coupling refers to the degree of direct knowledge that one element has of another. we can say an eg: A and B, only B change its behavior only when A change its behavior. A loosely coupled system can be easily broken down into definable elements.
Tight Coupling means one class is dependent on another class.
Loose Coupling means one class is dependent on interface rather than class.
In tight coupling, there are hard-coded dependency declared in methods.
In loose coupling, we must pass dependency externally at runtime instead of hard-coded. (Loose couple systems use interface for decreased dependency with class.)
For example, we have a system that can send output in two or more ways like JSON output, CSV output, etc.
Tight Coupled
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();
}
}
In the example above, if we want to change the output in JSON, then we need to find and change in the whole code, because Class1 is tightly coupled with the CSVOutputGenerator class.
Loose Coupled
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();
}
}
When two objects are loosely coupled, they can interact but have very little knowledge of
each other.
Loosely coupled designs allow us to build flexible OO systems that can handle change.
Observer design pattern is a good example for making classes loosely coupled, you can have a look on it in Wikipedia.
Loose coupling means that the degree of dependency between two components is very low.
Example: GSM SIM
Tight coupling means that the degree of dependency between two components is very high.
Example: CDMA Mobile
There are a lot of nice answers here using analogies, but a friend at work gave me an example that I liked more than all of the ones mentioned here... Eyes and Glasses!
Tight Coupling
Tight coupling would be the eyes. If I want to fix my vision, it's very expensive to get an eye transplant and holds a fair amount of risk. But what if the designer (being the human race) found a better way. Add a feature that is loosely coupled to the body so it can be easily changed! (yes.. glasses)
Loose coupling
I can easily replace my glasses without breaking my underlying vision. I can take off the glasses and my vision will be how it was before (not better or worse). Using different pairs of glasses changes how we see the world through our eyes with little risk and easy maintainability.
Summary
So next time someone asks you "who cares if my code is tightly-coupled?" The answer is all about effort to change, effort to maintain and risk of change.
So how is this done in C#? Interfaces and Dependency Injection!
EDIT
This is a good example of the Decorator pattern as well, where the eyes are the class we are decorating by meeting interface requirements but giving different functionality (e.g. sunglasses, reading glasses, magnifying glasses for jewelers, etc.)
An extract from my blog post on coupling:
What is Tight Coupling:-
As par above definition a Tightly Coupled Object is an object that needs to know about other objects and are usually highly dependent on each other's interfaces.
When we change one object in a tightly coupled application often it requires changes to a number of other objects. There is no problem in a small application we can easily identify the change. But in the case of a large applications these inter-dependencies are not always known by every consumer or other developers or there is many chance of future changes.
Let’s take a shopping cart demo code to understand the tight coupling:
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);
}
}
}
Problems with the above example
Tight Coupling creates some difficulties.
Here, OrderTotal() methods is give us complete amount for the current items of the carts. If we want to add the discount features in this cart system. It is very hard to do in above code because we have to make changes at every class as it is very tightly coupled.
The way I understand it is, that tightly coupled architecture does not provide a lot of flexibility for change when compared to loosely coupled architecture.
But in case of loosely coupled architectures, message formats or operating platforms or revamping the business logic does not impact the other end. If the system is taken down for a revamp, of course the other end will not be able to access the service for a while but other than that, the unchanged end can resume message exchange as it was before the revamp.
There are certain tools that provide dependency injection through their library, for example in .net we have ninject Library .
If you are going further in java then spring provides this capabilities.
Loosly coupled objects can be made by introducing Interfaces in your code, thats what these sources do.
Say in your code you are writing
Myclass m = new Myclass();
now this statement in your method says that you are dependent on myclass this is called a tightly coupled. Now you provide some constructor injection , or property injection and instantiating object then it will become loosly coupled.
It's about classes dependency rate to another ones which is so low in loosely coupled and so high in tightly coupled. To be clear in the service orientation architecture, services are loosely coupled to each other against monolithic which classes dependency to each other is on purpose
Loose coupling is and answer to to old style hardcoded dependencies and related issues issues like frequent recompilation when anything changes and code reuse. It stresses on implementing the worker logic in components and avoiding solution specific wire up code there.
Loose Coupling = IoC
See this for easier explanation.
Loose Coupling is the process of giving the dependency your class needs indirectly without providing all the information of the dependency(i.e in the from of interface) in case tight coupling you directly give in the dependency which is not good way of coding.
If an object's creation/existence dependents on another object which can't be tailored, its tight coupling. And, if the dependency can be tailored, its loose coupling. Consider an example in Java:
class Car {
private Engine engine = new Engine( "X_COMPANY" ); // this car is being created with "X_COMPANY" engine
// Other parts
public Car() {
// implemenation
}
}
The client of Car class can create one with ONLY "X_COMPANY" engine.
Consider breaking this coupling with ability to change that:
class Car {
private Engine engine;
// Other members
public Car( Engine engine ) { // this car can be created with any Engine type
this.engine = engine;
}
}
Now, a Car is not dependent on an engine of "X_COMPANY" as it can be created with types.
A Java specific note: using Java interfaces just for de-coupling sake is not a proper desing approach. In Java, an interface has a purpose - to act as a contract which intrisically provides de-coupling behavior/advantage.
Bill Rosmus's comment in accepted answer has a good explanation.
Loose and Tight coupling is about dependency one program component from another. This means dependency not only with programming class, it is about programming system components at all.
For example if you use only simple raw SQL Query to receive data from SQL Server this is Loose coupling. The opposite of Loose Coupling and simple raw SQL Query is Tight Coupling and Entity Framework Core. In Entity Framework Core you have to full model with POCO class in your code reflect database structure, than means any changing in database you have to reflect in code.
So, Tight Coupling between program code and database structure is Entity Framework, the opposite of this approach is refuse to use any ORM and refuse to have full mirror database structures in your program code.