Open anthonychavis opened 1 month ago
!!! if used for 3rd party APIs (or i guess anything), private methods could be used to verify/sanitize before outputting data ?
Java classes don't need destructors?
~wait! just realized main()
is static
!!!~
~I see how it's called! So, what I was saying about its convenience is legit!~
~you're not using main's param though~
SimpleIngection.main(<arr_of_args>);
~nope, java is very different.~
param typo = compile-time error?
public static void main(String[] args) {};
update: still thinking through it!
// service interface - aka contract - aka dependency of class that implements it ?
public interface Speak {
// contract methods
public String sayHi();
public Sting sayBye();
public String language();
}
// service/worker/dependency - defines the methods for a specific implementation of the interface - one of the classes that can vary for testing/feature-expansion - dependent on the interface ?; dependency of the injector class
public class SpeakEnglish implements Speak {
// define methods req'd by contract
@Override
public String sayHi() {
return "Hello";
}
@Override
public String sayBye() {
return "Goodbye";
}
@Override
public String language() {
return "English";
}
}
// other service/worker/dependency
public class SpeakCreole implements Speak {
// define methods req'd by contract
@Override
public String sayHi() {
return "Wah gwaan";
}
@Override
public String sayBye() {
return "Walk gud";
}
@Override
public String language() {
return "Jamaican Patois";
}
}
// injection class - knows it will speak, but doesn't care which language - shows how instantiation will occur - aka dependent class b/c provided another class to instantiate
public class SimpleIngection {
private Speak language;
// constructor injection
public SimpleIngection(Speak language) {
this.language = language;
}
// publicly available methods after injection
public String salutation() {
return language.sayHi();
}
public String weOut() {
return language.sayBye();
}
public String curLang() {
return language.language();
}
// private field initialized w/the dependency
// getters used to access dependency's public methods/fields; no getter = no access
}
// instantiate & use - demonstrates the DI - doesn't know how the service is created, but can use it
public class Main {
public static void main(String[] args) {
// SpeakEnglish service/worker/dependency instantiated & injected; assigned to var
SimpleIngection english = new SimpleIngection(new SpeakEnglish());
// SpeakCreole service/worker/dependency instantiated & injected; assigned to var
SimpleIngection creole = new SimpleIngection(new SpeakCreole());
// use
System.out.println("A greeting like " + english.salutation() + " in " + english.curLang() + " is " + creole.salutation() + " in " + creole.curLang() + ".");
}
}
// rough example of translator/language-learn app
the implements key word is used to type a class to the Speak data type
it looks similar to inheritance with extends
so, a service/worker class is kind of a parallel term to child class?
Java has single inheritance. It can only directly subclass one class, unlike C++. Interfaces are a way around it. Only the developer that uses that Interface, must define the methods defined.
you added 2 methods
3 total contract method
The contract (Interface) methods:
the methods in Speak must be defined (because contract?) in classes implementing its type
Yes.
yesterday I was first thinking you meant it should be mutable; like the interface type could change as needed here
Injection objects are not mutable. Once set, they are set. Or at least, they should be. My implementation is simple and doesn't disable it.
so, this injection class can be a "permanent fixture" somewhere in the code & what gets spit out will change based on whatever service/worker is plopped in as an arg!
Yes.
so, simpleIngection.salutation(); or simpleIngection.weOut(); can be in multiple files/modules but the service/worker only has to be inserted to the injection class in one place, right?
Yes.
so, when needing to change the data feed for some reason (guessing the database changed, using a test database, using a new database and didn't want to change the old database until making sure the new database worked correctly, or switching to a different 3rd party API, or something) it's easy swap out/in to see the changes across the entire codebase (or wherever the injection class is used), right ?
Exactly. In the real world, the developer using a package would set a configuration item to tell the software what class to use. The class will implement the method(s) and the software will inject it into it's code and do its thing. Database and cache is a good example.
the difference in instantiating the injection class b/c SSI's constructor doesn't get an arg
The major injection frameworks expect empty constructors and then introspect the classes (or use annotations) to call setup , tear down, status, etc methods. If they don't use annotations, the code will introspect the class to see if it implements and interface and then calls the methods.
Java classes don't need destructors?
No. The JVM handles it.
Thank you!
If this is right, think I got it! (still thinking through it a bit though) Not sure how to word this better yet:
english
will be assigned (via the injector) in one file. It'll then be imported to whichever files - could be 100s of files - need its data/functionality. In the one file where english
was initialized, can swap data w/a MockSpeakEnglish()
class for testing & the available data auto-changes in all 100s of files:
<!-- language_objects.java -->
// SimpleIngection english = new SimpleIngection(new SpeakEnglish());
SimpleIngection english = new SimpleIngection(new MockSpeakEnglish());
// SimpleIngection creole = new SimpleIngection(new SpeakCreole());
SimpleIngection creole = new SimpleIngection(new MockSpeakCreole());
However, if need to update the language classes to add features or phrases, would have to:
<!-- Speak.java -->
// no change
<!-- PharmacySpeak.java -->
public interface PharmacySpeak {
public String askSideEffects();
// insert other methods for common phrases used in convo while at pharmacy
}
<!-- SportsSpeak.java -->
public interface SportsSpeak {
public String askWhoWillWin();
// insert other methods for common phrases used in sports convos
}
<!-- SpeakEnglish.java -->
public class SpeakEnglish implements Speak, PharmacySpeak, SportsSpeak {
// update w/all contract methods
public String askSideEffects() {
// ...
}
}
<!-- SpeakCreole.java -->
public class SpeakCreole implements Speak, PharmacySpeak, SportsSpeak {
public String askWhoWillWin() {
// ...
}
// update w/all contract methods
}
<!-- SpeakFrench.java -->
public class SpeakFrench implements Speak {
// Speak contract methods
}
// There are a few options when building injector classes!
// If expanding only a couple languages at a time to quickly push those to production rather than waiting to update ALL languages before pushing to production, could still have generalized injector classes - new 1 for fully expanded languages, same old one for languages that haven't been updated. Then add in extra logic where the objects are used for null exceptions, I think
// there must be scenarios when having the generalized, all encompassing injector class is better than more specific injector classes, & vice versa
<!-- SimpleIngection.java -->
public class SimpleIngection {
// no change
}
<!-- DecoupledIngection.java -->
public class DecoupledIngection {
// kept separate for better "decoupling"
private Speak language;
private PharmacySpeak pharma;
private SportsSpeak sports;
// inject service/worker/dependency for all 3 params
public DecoupledIngection(Speak language, PharmacySpeak pharma, SportsSpeak sports) {
this.language = language;
this.pharma = pharma;
this.sports = sports;
}
// insert getters
// this class would grow too huge in this case; better to break it down!
}
// could allow the service/worker/dependency classes to grow huge & let the injector classes break them down; would still want to break those down too
<!-- InjectPharmaEnglish.java -->
// generalized to topic
public class InjectPharmaLang {
// still well decoupled
private PharmacySpeak pharmaLang;
public InjectPharmaLang(PharmacySpeak pharmaLang) {
this.pharmaLang = pharmaLang;
}
// insert pharma getters
}
[note: just realized the smiling emoji is actually a laughing emoji]
My today's understanding: DI via interfaces boils down to simply being a way to generically type an object that a class receives.
DI in general offers:
Still in the kitchen tryna jazz it up, so line nums might change, but this is what I've been cooking: https://github.com/anthonychavis/my-arduino-repo/blob/main/Theatre/Rabbit/Rabbit_Class/RabbitClass_Res.hpp
class start - line 48 dependency passed-by-ref - line 49 private constructor - line 134 static factory - line 150
was wondering, since I'm using a 3rd party library, is it best practive to enter that 3rd party class (Servo
) into its own dependent class then use that dependent class as a dependency for Rabbit
?
That way it wouldn't go into the class where it'll be used straight from the source. Was also thinking that if it would be best practice, it would be a good situation to utilize an interface, right?
thinking because with the interface i could be like, 'hey, i'm bringing this class in, but anyone who uses it is restricted to only use these methods.' like how you did in your example. ... think i just answered my own question
the program is very simple & functions as intended with far less lines of code, but want to practice. planning to organize the program into more files. definitely think the Rabbit class has grown too large. planning to split it.
recap
seeing the Java
the interface,
Speak
, defines the data type for classes to follow (like TS interface).implements
key word is used to type a class to theSpeak
data typeextends
the methods in
Speak
must be defined (because contract?) in classes implementing its type@Override
key word is used to (re)define the methodsfor "recap.2" you switched it to define a class
SpeakEnglish
&SpeakCreole
?"recap.3" is for the
SimpleIngection
class ?salutation
instead of objectSalutation
to a classSimpleIngection
sayIt
attribute tolanguage
attributeSpeak
interface type"recap.4"
:root
vars in css:root
simpleIngection.salutation();
orsimpleIngection.weOut();
can be in multiple files/modules but the service/worker only has to be inserted to the injection class in one place, right?"recap.5"
SimpleSetterIngection
(SSI) vsSimpleIngection
(SI)language
attribute via the setter in SSI line 34(will try to fully build it out in cpp with correct syntax)