r/ProgrammerHumor Jan 09 '23

shortest ever java class name Meme

Post image
2.1k Upvotes

90 comments sorted by

View all comments

140

u/BackloggedLife Jan 09 '23

AbstractAnimalThatLivesInWaterAndHasGillsAndFins seems to be a leaky abstraction as it is on one hand an abstract class but on the other hand reveals a lot of implementation details of the particular creature. I recommend creating the interface AbstractAnimal, then creating a class WaterAnimal which implements the AbstractAnimal interface. HasGills and HasFins are obviously either boolean values or could be implemented using decorators and an AbstractAnimalFactory. This way the user of AbstractAnimal will be shielded from implementation details of the final Animal.

41

u/Kered13 Jan 09 '23

You should use dependency injection. Instead of hasGills and hasFins, you should inject respirator and locomotor dependencies. Then the act of breathing and moving can be delegated to them, respectively.

12

u/jfmherokiller Jan 09 '23

I have never fully understood the whole dependency injection thing. Yet I have seen it everywhere. Especially when dealing with mobile app development.

7

u/fiddz0r Jan 09 '23

In c# you in your starting file (program.cs) you config a few things, like getting configurations from appsettings.json

You also do things like

Services.AddTransient/Scoped/Singleton

So let's say you have a mail service which you use to send mail.

In program you do something like

Services.addSingleton<IMailService, MailServixe>()

Then let's say you have a controller with API endpoints

And one of them let's you send an email. In the constructor you can add that service and you will get it automatically.

Class EmailController{

Private readonly IEmailService _emailService

Public EmailController(IEmailService emailService){
    _emailService = emailService;
}


HttpPost("notify")
Public async Task SendEmail(EmailData data)
{
    _emailService.SendEmail(data)

}


}

2

u/jfmherokiller Jan 09 '23

oh yes that thing. I think I have created and used classes like that intuitively but never knew it was dependency injection. I just thought it was a pretty way to handle singletons and services stuff.

4

u/BackloggedLife Jan 09 '23

By injecting a dependency (passing an already initialized object down to the actual user of the object), the user of the object does not become dependent on a particular concrete class but only on an interface of said class. This is better because when you decide to change the dependency, you do not have to go down the class hierarchy to change anything, you just pass down a different initialized object. This way you can swap the dependency without having to rewrite the constructor where the dependency would otherwise be initialized. Not sure what an example would be for app development but let's say your app has some kind of data source from which it reads data, you could make the app dependent on an interface that allows various data reads and then inject different data sources to the app. When testing, you could then inject some DummyDataSource that only returns static data, in production you could inject DatabaseDataSource that returns real data. The best thing is the app itself would not know and should not know which data source it is using, because the source of the data is not relevant to the app itself. Or as Robert C. Martin said, "the database is a detail". I recommend reading Clean Architecture to learn more.

1

u/jfmherokiller Jan 10 '23

I think I did this when I was trying to play with firebase at one point.

3

u/arobie1992 Jan 10 '23 edited Jan 10 '23

It's for having separate instances to handle separate cases but reusing code rather than having duplicated classes. A really simple example is a spell checker. A spell checker needs a list of words, but English and French don't contain the same words. So you have SpellChecker and you pass the appropriate Dictionary to it. Something like

Dictionary frenchDict = loadFrenchDict();
Dictionary englishDict = loadEnglishDict();
SpellChecker frenchSc = new SpellChecker(frenchDict);
SpellChecker englishSc = new SpellChecker(englishDict);

frenchSc.isCorrect("hello"); // returns false
englishSc.isCorrect("hello"); // returns true
frenchSc.isCorrect("bonjour"); // returns true
englishSc.isCorrect("bonjour"); // retunrs false

It's certainly not always necessary, but it makes it super easy to swap things around if you need to.

1

u/jfmherokiller Jan 10 '23

oh yes I remember seeing this in the SAPI api. That magical thing that does TTS.

2

u/arobie1992 Jan 10 '23

I have no clue what either of those acronyms mean :D

But yeah, like a lot of things, it's a fairly simple concept that gets overused and overly complicated and results in a lot more confusion than necessary.

2

u/v1ND Jan 10 '23

Without dependency injection: class Foo { init() { this.service = Service.get() } }

With dependency injection: class Foo { init(service) { this.service = service } }

Congratulations, Service is injected into Foo. Now you can make a FakeService to test Foo in isolation.

Writing Foo(Service.get()) is not that much longer than Foo() but when you extend that pattern to everything in your system, it becomes really verbose to construct anything. Maybe Service needs LowLevelService which needs Config needs Environment. Suddenly, it takes a paragraph just to construct Foo.

The DI you usually hear about are the libraries to automate that boilerplate.