Tuesday Brown Bag

Download Report

Transcript Tuesday Brown Bag

Tuesday
Brown Bag
Inversion of
Control
Or why the Factory Pattern is Bad
7/17/2015
Slide 1
Presentation Contents
• Theory behind Inversion of Control
• What it is and why you should use it
• How IoC has been implemented:
•
•
•
•
Pico and Nano Containers
Spring Framework
Google’s Guice
Ways to role yer own with scripts
• Alternatives
7/17/2015
Slide 2
OOP Failure
• Objects are seldom reusable
• Objects usually have direct dependencies
• Unit testing some times involves starting other
objects … or even the entire application!
• Fault of “object normalization”
• Objects often can’t be replaced even if
both versions adhere to the same interface
7/17/2015
Slide 3
The Problem
• Separation of code through an API
• Client is dependent on implementation
• Difficult to unit test the client without server
Client
Aserver s =
new Aserver();
s.doIt();
7/17/2015
Server
public class Aserver
{
public doIt() {
...
}
}
Slide 4
Use an Interface
• Client works through an Interface
• Client is still dependent on implementation
• Still can’t unit test the client without server
Client
Iserver s =
new Aserver();
s.doIt();
7/17/2015
Server Interface
interface Iserver
{
public doIt();
}
Server
public class Aserver
implements Iserver
{
public doIt() {
...
}
}
Slide 5
Factory Pattern
• Create a Factory class
• Mediates between the client and server
• Can test the client with mock objects
public class ServerFactory {
boolean testing = false;
public static Iserver getInstance() {
if (testing)
return new MockServer();
else
return new Aserver();
}
}
7/17/2015
Slide 6
Inversion of Control
• Factory works for simple situations
• IoC works better for large applications
• Client does not retrieve a server instance
• Client is given a server instance
public class Client
{
Iserver server;
public void setServer (Iserver s) {
this.server = s;
}
...
}
7/17/2015
Slide 7
IoC Package Layout
Client
ServerInterface
...
Iserver server;
void setServer(
Iserver s) {
server = s;
}
interface Iserver
{
public doIt();
}
Unit Tests
void testClient {
Client client = new Client();
Iserver ts = new MockSvr();
Client.setServer(ts);
...
}
7/17/2015
Server
public class Aserver
implements Iserver
{
public doIt() {
...
}
}
MockServer
public class MockSvr
implements Iserver
{
public doIt() {
...
}
}
Slide 8
Hooking up Client / Server
• Can simply create a binding class
• Dependency is now higher (application level)
• All bindings need to be explicit
• However, some bindings are obvious
• A client could require a MailServer instance, but
if only one class that implements the interface is
given, why require an explicit binding?
• Could create a client factory, but now you
have same amount of code without IoC
7/17/2015
Slide 9
IoC Container Frameworks
• Build applications by binding independent
components together
• Components are POJOs (esp. JavaBeans)
• Each framework binds them differently:
• Bindings using special Java code
• Specify bindings with XML or scripting lang
• Describe bindings with Java annotations
7/17/2015
Slide 10
Why use IoC Framworks?
• Modularize how dependencies between
parts of your application are laced up
• To improve the testability of your code
• To improve component configuration
• Less code due to automatic binding
• Components have a chance at being
reused
7/17/2015
Slide 11
Pico Container
• Uses Java code to do the bindings:
MutablePicoContainer pico = new DefaultPicoContainer();
pico.registerComponentImplementation(Client.class);
pico.registerComponentImplementation(Interface.class,
Server.class);
• The application goes through container:
Client c = (Client) pico.getComponentInstance(Client.class);
See www.picocontainer.org
7/17/2015
Slide 12
Nano Container
• Builds on top of Pico Container
• Component binding is not compiled:
• Done by class name (using reflection)
• Done by scripting languages (Groovy, Ruby)
builder = new
org.nanocontainer.script.groovy.NanoContainerBuilder()
nano = builder.container {
component(class:Girl)
component(class:Boy)
}
See nanocontainer.codehaus.org
7/17/2015
Slide 13
Spring Framework
• Component bindings (and configuration)
done using XML:
<beans>
<bean id=”myclient” class=”Client">
<property name="username" value="someone" />
</bean>
<bean id=”myserver” class=”Server”/>
</beans>
See www.springframework.org
7/17/2015
Slide 14
Google’s Guice
• Component bindings done via annotations:
public class Client {
private final IServer service;
@Inject
public Client(IServer service) {
this.service = service;
}
• Default implementations of an Interface:
@ImplementedBy(ServiceImpl.class)
public interface IServer {
...
}
See http://code.google.com/p/google-guice/
7/17/2015
Slide 15
IoC Container Comparison
• Spring is the most complete / mature
• The XML file becomes unwieldy
• Has great web application solution
• Guice is young, but promising
• Requires Java 5
• All code is in Java, however
• Nano’s scripting capabilities intrigue me
• Pico is only IoC and component lifecycle
7/17/2015
Slide 16
Roll Yer Own - Scripts
• Bind components in scripts with Java 6
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine engine = m.getEngineByName("jruby");
engine.getContext().setAttribute( ”client", new Client() );
engine.getContext().setAttribute( ”server", new Server() );
engine.eval(bindingScript, context);
$client.setServer ( $server );
...
$client.doIt();
• Component instantiation in one file, and
bindings are in another (the script)
7/17/2015
Slide 17
Other Options
• Plugin interfaces (built with Reflection)
• Components are built against a particular API
• Service Locator (e.g. JNDI)
• Built against API
• Distributed
• Configuration/deployment can be a nightmare
• JINI
• Really only makes sense if it is distributed
7/17/2015
Slide 18