![Page 1: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/1.jpg)
Program to an Interface
(a.k.a. - P2I)
Not an Implementation
Early in the WeatherStation constructor:
Barometer bar = new Barometer() ;
Why is this problematic:
• WeatherStation depends on a specific implementation of a
Barometer.
• In particular, here a simulated Barometer!
• Each different type of Barometer makes us change the
WeatherStation.
• Or jury-rig some sort of way of loading the "right" Barometer.
• Reduces the reusability of WeatherStation in different contexts.
![Page 2: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/2.jpg)
P2I: Factories
Go ask someone else for what we need:
Some other known class (static factories):
java.util.System:
public Console console() ;
– Get object to read and write to the application's console.
– How this is done is inherently system dependent.
– Different on Windows, Linux, Mac
![Page 3: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/3.jpg)
P2I: Factories
Go ask someone else for what we need:
Some other known class (static factories)
Some other known object (dynamic factories)
java.util.Runtime:
Runtime rt = Runtime.getRuntime() ;
. . .
Process p = rt.exec("some system command") ;
– Processes are inherently system dependent.
– As is how to create one to execute a command.
![Page 4: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/4.jpg)
Factory Method Pattern
Often we have related, parallel hierarchies.
Factory method uses an object in one hierarchy to retrieve an
appropriate object from the other hierarchy.
![Page 5: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/5.jpg)
Factory Method Pattern
Often we have related, parallel hierarchies.
Factory method uses an object in one hierarchy to retrieve an
appropriate object from the other hierarchy.
Example: Java Collections and their Iterators.
![Page 6: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/6.jpg)
Factory Method Pattern
Example: Java Collections and their Iterators.
List theCollection = new ArrayList();
Iterator iter = theCollection.iterator();
while( iter.hasNext() ) {
process( iter.next() );
}
![Page 7: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/7.jpg)
Barometer & Factory - 1
First, use an abstract barometer class:
public abstract class Barometer {
public static Barometer createBarometer() { ... }
abstract public double pressure() ;
}
Next, change the simulated barometer class and all other barometer
classes to
1. Have a different name, and
2. Extend the abstract class above
public class SimBarometer extends Barometer { ... }
public class RealBarometer extends Barometer { ... }
![Page 8: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/8.jpg)
Barometer & Factory - 2
Change the factory createBarometer() method to return the desired
specific, concrete barometer object.
public static Barometer createBarometer() {
return new SimBarometer() ; // or something else
}
Inside the WeatherStation, use the factory to get the Barometer to
use:
public WeatherStation {
private final Barometer bar ;
public WeatherStation() {
bar = Barometer.createBarometer() ;
}
. . .
![Page 9: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/9.jpg)
P2I: Factory Pattern Points
Factory Approach Advantages
• Decouple the class needing an object from the creation of a concrete
object.
• Always get compatible objects.
Factory Approach Disadvantages
• Still have to know where the factory is.
• Coupled to the factory class or object.
• Can we decouple even more? Yes - dependency injection.
![Page 10: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/10.jpg)
P2I: Dependency Injection Pattern
Dependency Injection - target object (e.g., WeatherStation) is given
the objects it needs (e.g., barometer and temperature sensor) from the
surrounding environment:
• Via constructor arguments.
• Via specific injection methods.
In fact, we've already seen this:
![Page 11: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/11.jpg)
P2I: Dependency Injection Pattern
Dependency Injection - target object (here WeatherStation) is given the
object it needs from the surrounding environment:
• Via constructor arguments.
• Via specific injection methods.
In fact, we've already seen this:
public class TextUI implements Observer {
private final WeatherStation station ;
public TextUI(WeatherStation station) {
this.station = station ;
this.station.addObserver(this) ;
}
Anything compatible withWeatherStation can besubstituted.
![Page 12: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/12.jpg)
Dependency Injection & Barometer - 1
First, define a barometer interface:
public interface Barometer {
public double pressure() ;
}
Next, change the simulated barometer class and all other barometer
classes to
1. Have a different name, and
2. Implement the interface above
public class SimBarometer implements Barometer { ... }
public class RealBarometer implements Barometer { ... }
![Page 13: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/13.jpg)
Dependency Injection & Barometer - 2
Change the public static void main() method to inject whichever
concrete barometer we want:
public static void main(String[] args) {
. . .
WeatherStation ws =
new WeatherStation( new SimBarometer() );
}
In the WeatherStation constructor, save the injected Barometer:
public WeatherStation {
private final Barometer bar ;
public WeatherStation(Barometer bar) {
this.bar = bar ;
}
. . .
![Page 14: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/14.jpg)
Now To The Temperature Senson
Early in the WeatherStation constructor
KelvinTempSensor sensor = new KelvinTempSensor() ;
On the surface this looks exactly like Barometer:
• We create a concrete sensor object in the weather station.
• This limits weather station reusability with different sensors.
• So:
– Define an interface, say IKelvinTempSensor.
– Implement the interface for all real & simulated sensor classes.
– Create the desired concrete sensor in main or other driver method.
– Inject this object into the WeatherStation constructor.
But there is more here than meets the eye!
![Page 15: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/15.jpg)
Problems With The Temperature Sensor
The interface represents an "odd" notion of what temperature looks like:
– Scaled integer from 0 to 65535?
– Measures up to 655.35 °K?
– That's a weird upper bound - why is it there?
The designers thought the problem was selecting an integrating the best
sensor.
![Page 16: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/16.jpg)
Problems With The Temperature Sensor
The interface represents an "odd" notion of what temperature looks like:
– Scaled integer from 0 to 65535?
– Measures up to 655.35 °K?
– That's a weird upper bound - why is it there?
The designers thought the problem was selecting an integrating the best
sensor.
The designers were WRONG!
The real problem is how to hide the details of specific sensor used from
the weather station.
All the weather station needs is a general value representing the
temperature in some reasonable form.
![Page 17: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/17.jpg)
Dependency Inversion Principle
Low-level components should depend on high-level components, not the
other way around.
- OR -
High-level components should not depend on low-level components.
Both should depend on abstractions.
Abstractions should not depend on details (of low level entities).
Details should depend on abstractions.
- OR -
High-level components control the interface to low-level components.
![Page 18: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/18.jpg)
![Page 19: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/19.jpg)
What About Existing KelvinTempSensor?
Approach #1: Change the code
• Make the KelvinTempSensor class implement ITempSensor.
• Change the body of the code to convert from the scaled integer in
°K to a double precision number in °C.
• Replace the reading() method with getCelsius().
![Page 20: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/20.jpg)
What About Existing KelvinTempSensor?
Approach #1: Change the code
• Make the KelvinTempSensor class implement ITempSensor.
• Change the body of the code to convert from the scaled integer in
°K to a double precision number in °C.
• Replace the reading() method with getCelsius().
Potential problems:
• Small changes here, but in general there would be many changes.
• We might not have the source code, only a precompiled .class or .jar
file.
![Page 21: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/21.jpg)
What About Existing KelvinTempSensor?
Approach #1: Change the code
• Make the KelvinTempSensor class implement ITempSensor.
• Change the body of the code to convert from the scaled integer in°K to a double precision number in °C.
• Replace the reading() method with getCelsius().
Potential problems:
• Small changes here, but in general there would be many changes.
• We might not have the source code, only a precompiled .class or .jar file.
Approach #2: Create an Adapter.
![Page 22: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/22.jpg)
Adapters
What are adapters for?
• Have an existing entity (2-prong outlet, temperature sensor class).
• Which does what is required (deliver A/C electricity, provides the
temperature).
• But in a way we can't use (no grounding, temperature in scaled
Kelvin).
• So we create an adapter (3-prong adapter, temperature adapter
class).
In software design, this is the goal of the Adapter Pattern.
![Page 23: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/23.jpg)
Reasons for Software Adapters
Class of the object we at hand has:
• Different method names.
• Different return types or values.
• Different argument types or counts.
• Different partitioning of class responsibilities.
Usually a combination of the above.
![Page 24: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/24.jpg)
Software Adapter UML
![Page 25: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/25.jpg)
Temperature Sensor Adapterpublic interface ITempSensor {
public double getCelsius() ;
}
. . .
public class KTempAdapter implements ITempSensor {
private KelvinTempSensor kts = new KelvinTempSensor() ;
private K2C_CONVERT = -27315 ;
public double getCelsius() {
return (kts.reading() + K2C_CONVERT) / 100.0 ;
}
}
To use this in our application:1. Create a KTempAdapter object in the UI main method.
2. Inject this into the WeatherStation as a constructor argument.
3. The WeatherStation argument is, of course, of type ITempSensor.
4. Change WeatherStation code dependent on KelvinTempSensor to use what is returned by the ITempSensor objects.
![Page 26: Program to an Interface (a.k.a. - P2I) Not an Implementationswen-383/slides/instructor... · Program to an Interface (a.k.a. - P2I) Not an Implementation Early in the WeatherStation](https://reader035.vdocument.in/reader035/viewer/2022071013/5fcb1188947220465b49205b/html5/thumbnails/26.jpg)
Design Caveats (Uncle Bob Martin)Woe is the designer who prematurely decides on a database, and then finds that flat files would have been sufficient.
Woe is the designer who prematurely decides upon a web-server, only to find that all the team really needed was a simple socket interface.
Woe is the team whose designers prematurely impose a framework upon them, only to find that the framework provides powers they don't need and adds constraints they can't live with.
Blessed is the team whose designers have provided the means by which all these decisions can be deferred until there is enough information to make them.
Blessed is the team whose designers have so isolated them from slow and resource hungry IO devices and frameworks that they can create fast and lightweight test environments.
Blessed is the team whose designers care about what really matters, and defer those things that don't.
https://sites.google.com/site/unclebobconsultingllc/