SlideShare uma empresa Scribd logo
1 de 69
Башкирцев (Старовер) Станислав
ctapobep@javatalks.ru
JavaTalks
OOD Principles
2
План презентации
• Intro
• Don’t Repeat Yourself
• Open Closed
• Single Responsibility
• Interface Segregation
• Inversion of Control
• Liskov’s Substitution
• Q/A
3
OOD Principles. What’s that?
• Recipes, best practices how to write
• Clean, easy to understand code
• Maintainable (flexible, extendable) code
DRY
Don’t Repeat Yourself
• Don’t duplicate code
5
Without DRY
st.executeQuery("select user.name, user.password from user where id=?");
If something changes?
st.executeQuery("select user.username, user.password from user where id=?");
With DRY
st.executeQuery("select user.name, user.password from user where id=?");
public User getUser(Long id) {…}
If something changes?
st.executeQuery("select user.username, user.password from user where id=?");
public User getUser(Long id) {…}
DRY
Don’t Repeat Yourself
• Don’t duplicate code
• Names should be clear
Not clear names
public class Utils {
public static Connection createConnection(String... params){...}
public static Object[] getSortedArray(Object[] array){...}
}
1. No one would guess to look sorting method in this class.
2. Newbie always would write his own implementation.
Correct DRY
public class ArrayUtils {
public static Object[] getSortedArray(Object[] array) {…}
}
public class DatabaseUtils {
public static Connection createConnection(String... params) {...}
}
clear, well-defined class names
DRY
Don’t Repeat Yourself
• Don’t duplicate code
• Names should be clear
• Location should be clear
Not clear location
package ru.jt.transformer.csv;
public class ArrayUtils {
public static Object[] getSortedArray(Object[] array) {...}
}
No one would look for array utilities in such package
DRY. Pros & Cons
Pros:
• Changes impact local area
• Once written is not repeated
• No ”new” error prone solutions
Cons:
• Amount of classes grows
OCP
Open Closed Principle - code should be closed
for modification, but open for extension.
OCP. Example
I want my clients to be able to
see results of past games. Let’s
keep up with NHL & NBA games..
1. American customer
2. His thoughts
3. His ill imagination
OCP. Example
public class SportInfoParser implements SportInfoParser {
public SportInfo parseSportInfo(String[] sportInfoArray) {
SportInfo sportInfo = null;
if ("nba".equals(sportInfoArray[0])) {
NbaSportInfo nbaSportInfo = new NbaSportInfo();
Map<Long, Integer> scores = new HashMap<Long, Integer>();
scores.put(Long.parseLong(sportInfoArray[12]), Integer.parseInt(sportInfoArray[13]));
nbaSportInfo.setScores(scores);
sportInfo = nbaSportInfo;
} else if ("nhl".equals(sportInfoArray[0])) {
NhlSportInfo nhlSportInfo = new NhlSportInfo();
nhlSportInfo.setSlapShotCount(1);
}
return sportInfo;
}
}
Base class
Creates specific
objects according to...
OCP. Example
Great! A lot of new clients, a lot of
money from ads. But.. Would be
great if my cliends would be able
to get info about MLB games too!
OCP. Example
public class SportInfoParser implements SportInfoParser {
public SportInfo parseSportInfo(String[] sportInfoArray) {
SportInfo sportInfo = null;
if ("nba".equalsIgnoreCase(sportInfoArray[0])) {
NbaSportInfo nbaSportInfo = new NbaSportInfo();
Map<Long, Integer> scores = new HashMap<Long, Integer>();
scores.put(Long.parseLong(sportInfoArray[12]), Integer.parseInt(sportInfoArray[13]));
nbaSportInfo.setScores(scores);
sportInfo = nbaSportInfo;
} else if ("nhl".equalsIgnoreCase(sportInfoArray[0])) {
NhlSportInfo nhlSportInfo = new NhlSportInfo();
nhlSportInfo.setSlapShotCount(1);
} else if(sportInfoArray[0].equalsIgnoreCase("mlb")){
MlbSportInfo mlbSportInfo = new MlbSportInfo();
mlbSportInfo.setHits(Integer.parseInt(sportInfoArray[1]));
mlbSportInfo.setRuns(Integer.parseInt(sportInfoArray[2]));
}
return sportInfo;
}
}
New league
was added
We are changing
already working class!
OCP. Example
Why my clients see errors
on every page?!! I pay you
for work, not for errors! I
loose my clients, make the
program work right!
OCP. Example
public class SportInfoParser implements SportInfoParser {
public SportInfo parseSportInfo(String[] sportInfoArray) {
SportInfo sportInfo = null;
if ("nba".equalsIgnoreCase(sportInfoArray[0])) {
NbaSportInfo nbaSportInfo = new NbaSportInfo();
Map<Long, Integer> scores = new HashMap<Long, Integer>();
scores.put(Long.parseLong(sportInfoArray[12]), Integer.parseInt(sportInfoArray[13]));
nbaSportInfo.setScores(scores);
sportInfo = nbaSportInfo;
} else if ("nhl".equalsIgnoreCase(sportInfoArray[0])) {
NhlSportInfo nhlSportInfo = new NhlSportInfo();
nhlSportInfo.setSlapShotCount(1);
} else if(sportInfoArray[0].equalsIgnoreCase("mlb")){
MlbSportInfo mlbSportInfo = new MlbSportInfo();
mlbSportInfo.setHits(Integer.parseInt(sportInfoArray[1]));
mlbSportInfo.setRuns(Integer.parseInt(sportInfoArray[2]));
}
return sportInfo;
}
}
Element of array is
compared with league name
– NPE is possible!
OCP. Moral
This example shows that changing code that
already works is always bad idea.
Follow OCP to escape this!
OCP. Example
public class SportInfoParser implements SportInfoParser {
private Map<String, SportInfoBuilder> builders;
public SportInfoParserEnhanced(Map<String, SportInfoBuilder> builders) {
this.builders = builders;
}
public SportInfo parseSportInfo(String[] sportInfoArray) {
SportInfoBuilder builder = builders.get(sportInfoArray[0]);
if(builder != null){
return builder.build(sportInfoArray);
}
return null;
}
}
MlbSportInfoBuilder
NbaSportInfoBuilder NhlSportInfoBuilder
public class NbaSportInfoBuilder implements SportInfoBuilder {
public SportInfo build(String[] sportInfoArray) {
NbaSportInfo nbaSportInfo = new NbaSportInfo();
Map<Long, Integer> scores = new HashMap<Long, Integer>();
scores.put(…, …);
nbaSportInfo.setScores(scores);
return nbaSportInfo;
}
}
OCP. Example
Great! You job satisfies me!
But now I want WNBA to be
added 
OCP. Example
public class SportInfoParser implements SportInfoParser {
private Map<String, SportInfoBuilder> builders;
public SportInfoParserEnhanced(Map<String, SportInfoBuilder> builders) {
this.builders = builders;
}
public SportInfo parseSportInfo(String[] sportInfoArray) {
SportInfoBuilder builder = builders.get(sportInfoArray[0]);
if(builder != null){
return builder.build(sportInfoArray);
}
return null;
}
}
MlbSportInfoBuilder
NbaSportInfoBuilder NhlSportInfoBuilder
WnbaSportInfoBuilder
New league was added without
changing single line of code!
OCP. How it works
OCP uses:
• Delegation
• Inheritance
OCP. Pros & Cons
Pros:
• Adding new functionality without legacy code
being changed
Cons:
• May complicate system because of amount of
classes being grown
SRP
Single Responsibility Principle:
• Single class should have a single responsibility
• Class should have only one reason to change
SRP. Random thoughts
public class CurrencyConverter {
public BigDecimal convert(Currency from, Currency to, BigDecimal amount) {
// gets connection to some online service and asks it to convert currency
// parses the answer and returns results
}
public BigDecimal getInflationIndex(Currency currency, Date from, Date to) {
// gets connection to some online service to get data about
// currency inflation for specified period
}
}
Hm.. Strange that inflation is
counted in CurrencyConverter..
Hm.. What if format of
currency service changes?
What if the format of inflation
service changes?
We’ll have to change this
class in both cases!
It’s not intuitive!
It’s overloaded!
We have to do something!
SRP. Separate Responsibilities
public class CurrencyConverter {
public BigDecimal convert(Currency from, Currency to, BigDecimal amount) {
// gets connection to some online service and asks it to convert currency
// parses the answer and returns results
}
}
public class InflationIndexCounter {
public BigDecimal getInflationIndex(Currency currency, Date from, Date to) {
// gets connection to some online service to get data about
// currency inflation for specified period
}
}
Hm.. What if format of
currency service changes? We
change CurrencyConverter!
Hm.. What if format of
inflation service changes? We
change InflationIndexCounter!
SRP & DRY
Again two responsibilities:
Authentication & getting user
from database
public class UserAuthenticator {
public boolean authenticate(String username, String password){
User user = getUser(username);
return user.getPassword().equals(password);
}
private User getUser(String username){
st.executeQuery("select user.name, user.password from user where id=?");
// something's here
return user;
}
}
DRY violation!
SRP. Delegating responsibilities
public class UserAuthenticator {
private UserDetailsService userDetailsService;
public UserAuthenticator(UserDetailsService service) {
userDetailsService = service;
}
public boolean authenticate(String username, String password){
User user = userDetailsService.getUser(username);
return user.getPassword().equals(password);
}
}
Now we don’t work
directly with database!
If we would want to use
ORM, UserAuthenticator
won’t change!
SRP. Pros & Cons
Pros:
• Helps to follow DRY
• Lowers chances to change single class
• Class names correspond to what they do
Cons:
• May complecate system by adding too much
new classes
ISP
Interface Segregation Principle – client code
shouldn’t be obligated to depend on
interfaces it doesn’t use.
ISP. Example
interface Person {
void goToWork();
void withdrawSalary();
void eat();
}
Base interface of
the person.
All these methods are
useful for current
implementation of
person.
ISP. Extra methods
interface Person {
void goToWork();
void withdrawSalary();
void eat();
}
But we’re writting new
module that considers a
person only as a human
being. So we need only
one method eat()
public class PersonImpl implements Person {
public void goToWork() {
throw new UnsupportedOperationException();
}
public void withdrawSalary() {
throw new UnsupportedOperationException();
}
public void eat() {
//some real implementation
}
}
So our new
implementation has two
extra methods.
ISP. What these methods do?!
ISP. Fat/Polluted Interfaces
interface Person {
void goToWork();
void withdrawSalary();
void eat();
}
It’s fat
It’s POLLUTED
ISP. Interface Separating
public interface Person {
void eat();
}
public interface Worker {
void goToWork();
void withdrawSalary();
}
We separated Person
into Person & Worker.
Two conceptually
different interfaces.
ISP. No extra methods
public class PersonImpl implements Person {
public void eat() {
//some real implementation
}
}
Now we have only
needed methods.
ISP. Legacy code
What if we have ready
implementation, but we
don’t want to use fat
interface?
public class FatPersonImpl implements FatPerson {
public void goToWork() {
//some real implementation
}
public void withdrawSalary() {
//some real implementation
}
public void eat() {
//some real implementation
}
}
ISP. Use Adapters
public class PersonAdapter implements Person {
private FatPerson fatPerson;
public PersonAdapter(FatPerson fatPerson) {
this.fatPerson = fatPerson;
}
public void eat() {
fatPerson.eat();
}
}
Thin interface
Fat interface
ISP. Pros & Cons
Pros:
• No need to implement unnecessary methods
• Client code sees only what it should see
Cons:
• Adding additional interfaces
IoCP
Invertion of Control Principle says:
• Code to abstraction, not to implementation
• Objects that use other objects, shouldn’t
create latter ones
IoCP. Coding to implementation
public interface HtmlParser {
HtmlDocument parseUrl(String url);
}
public class Crawler {
public void saveHtmlDocument() {
DomBasedHtmlParser parser = new DomBasedHtmlParser();
HtmlDocument document = parser.parseUrl("http://javatalks.ru");
save(document, "jt-index");
}
public void save(HtmlDocument htmlDocument, String pageName) {
// logic of saving
}
}
public class DomBasedHtmlParser implements HtmlParser {
public HtmlDocument parseUrl(String url) {
// getting html page as stream
//parsing it with DOM parser
//creating HtmlDocument
return htmlDocuments;
}
}
IoCP. How to test Crawler?
public class Crawler {
public void saveHtmlDocument() {
DomBasedHtmlParser parser = new DomBasedHtmlParser();
HtmlDocument document = parser.parseUrl("http://javatalks.ru");
save(document, "jt-index");
}
public void save(HtmlDocument htmlDocument, String pageName) {
// logic of saving
}
}
It’s impossible to write
unit test for Crawler,
because you cannot
mock parser.
IoCP. Let’s inject
public class Crawler {
private DomBasedHtmlParser parser;
public Crawler(DomBasedHtmlParser parser) {
this.parser = parser;
}
public void saveHtmlDocument() {
HtmlDocument document = parser.parseUrl("http://javatalks.ru");
save(document, "jt-index");
}
public void save(HtmlDocument htmlDocument, String pageName) {
// logic of saving
}
}
Crawler crawler = new Crawler(someMockParser);
Now you can specify
parser through
constructor. You can
inject dummy object
while testing.
IoCP. Again doesn’t work
Your parser doesn’t
work with HTML that
isn’t a valid XML!
IoCP. New Implementation
HtmlParser
DomBasedHtmlParser
EnhancedHtmlParser
IoCP. But how do we replace?
public class Crawler {
private DomBasedHtmlParser parser;
public Crawler(DomBasedHtmlParser parser) {
this.parser = parser;
}
public void saveHtmlDocument() {
HtmlDocument document = parser.parseUrl("http://javatalks.ru");
save(document, "jt-index");
}
public void save(HtmlDocument htmlDocument, String pageName) {
// logic of saving
}
}We cannot specify
another implementaion!
IoCP. Let’s code to interface
public class Crawler {
private HtmlParser parser;
public Crawler(HtmlParser parser) {
this.parser = parser;
}
public void saveHtmlDocument() {
HtmlDocument document = parser.parseUrl("http://javatalks.ru");
save(document, "jt-index");
}
public void save(HtmlDocument htmlDocument, String pageName) {
// logic of saving
}
}
Now we use interface, so
we can specify enhanced
implementation of
parser.
IoCP. Another look
How do we inject objects if we work on
framework/library? We cannot use IoC
Containers, our clients don’t allow us extra
dependencies, they don’t want to depend on
Spring or Guice. We need leightweight
decision.
IoCP. Let’s use Factories
public class Crawler{
private HtmlParser parser = ParserFactory.getHtmlParser();
public void saveHtmlDocument() {
HtmlDocument document = parser.parseUrl("http://javatalks.ru");
save(document, "jt-index");
}
}
Let’s use Factories! Hm.. But we cannot
write unit tests again!
IoCP. Let’s mix
public class Crawler{
private HtmlParser parser = ParserFactory.getHtmlParser();
public void saveHtmlDocument() {
HtmlDocument document = parser.parseUrl("http://javatalks.ru");
save(document, "jt-index");
}
public void setParser(HtmlParser parser) {
this.parser = parser;
}
}
We have both: setter and
factory in the same class.
Now we have default
implementation and
possibility to change
default behavior.
IoCP. Pros & Cons
Pros:
• Classes don’t depend on concrete
implementation
• Allows easily change implementation
• Allows write good unit tests
Cons:
• Creating additional interfaces
• Creating Factories/depending on IoC
containers
LSP
Liskov’s Substitution Principle – derived types
must be completely substitutable for their
base types.
LSP declares how to use inheritance correctly.
LSP. java.util.List
List list = new ArrayList(); List list = new LinkedList();
list.get(1);
Would be strange if these
implementation would do
different things here
LSP. Emu doesn’t fly!
class Bird extends Animal {
@Override //walk is overriden from Animal
public void walk() {...}
@Override //makeOffspring() is overriden from Animal
public void makeOffspring() {...};
//was added
public void fly() {...}
}
class Emu extend Bird {
public void makeOffspring() {...}
}
But emu doesn’t fly!
LSP. Emu indeed doesn’t fly
class Bird extends Animal {
@Override //walk is overriden from Animal
public void walk() {...}
@Override //makeOffspring() is overriden from Animal
public void makeOffspring() {...}
}
class FlyingBird extends Bird {
public void fly() {...}
}
class Emu extends Bird {
@Override
public void makeOffspring(){..}
}
Simply birds.
Flying birds.
Emu is simply a bird.
It doesn’t have extra
methods.
LSP. Array example
interface ArraySorter {
Object[] parse(Object []args);
}
class DefaultArraySorter implements ArraySorter {
public Object[] sort(Object []array){
Object[] result = array.clone();
...
}
}
Default implementation.
It’s a temporal class that
uses unefficient approach.
But it does it’s work
correctly.
LSP. Array example
interface ArraySorter {
Object[] parse(Object []args);
}
At last we wrote enhanced
implementation that’s
really efficient.
class QuickArraySorter implements ArraySorter {
public Object[] sort(Object []array){
Object[] result = array;
...
}
}
LSP. Again bugs!
Your system always
throws errors! It’s a
chaos!!
LSP. Array example
class QuickArraySorter implements ArraySorter {
public Object[] sort(Object []array){
Object[] result = array;
...
}
}
It sorts the original array!
We have problems with
synchronization.
Implementation does its
work, but it has side
effects. It doesn’t satisfy
interface contract!
We cannot simply replace
one implementation with
another one, because they
differ!
We should correct its
behaviour to copy original
array and work with its copy.
LSP & equals()
public class Point {
private int x;
private int y;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Point)) return false;
Point point = (Point) o;
if (x != point.x) return false;
if (y != point.y) return false;
return true;
}
}
public class ColoredPoint extends Point {
private int color;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ColoredPoint)) return false;
if (!super.equals(o)) return false;
ColoredPoint that = (ColoredPoint) o;
if (color != that.color) return false;
return true;
}
}
Colored point extends
simple point and adds new
field – color.
But it works only with
ColoredPoint!
LSP & equals
Point point = new Point(1, 1);
ColoredPoint coloredPoint = new ColoredPoint(1, 1, 1);
System.out.println(point.equals(coloredPoint));
System.out.println(coloredPoint.equals(point));
This will print:
true
false
This violates equals()
contract!
There is no correct
dicision in this situation!
LSP & equals()
public class ColoredPoint {
private Point point;
private int color;
}
The only correct way here
is to use delegation
instead of inheritance.
LSP & exceptions
List list = new OurSuperPuperImplementation();
list.iterator().next();
What if this method in
our implementation
threw IOException?
How would we know
about that? We work
with interface List, not
with implementation!
That’s why Java
doesn’t allow us to
throw any checked
exception that are not
declared in base class.
LSP. Pros & Cons
Pros:
• Allows not to think about concrete
implementation, but code to abstraction
• Unambiguously defines contract all
implementers should follow
• Allows to interchange implementation
correctly, without side effects
The End
Q/A

Mais conteúdo relacionado

Mais procurados

TypeScript - All you ever wanted to know - Tech Talk by Epic Labs
TypeScript - All you ever wanted to know - Tech Talk by Epic LabsTypeScript - All you ever wanted to know - Tech Talk by Epic Labs
TypeScript - All you ever wanted to know - Tech Talk by Epic LabsAlfonso Peletier
 
Clean code in JavaScript
Clean code in JavaScriptClean code in JavaScript
Clean code in JavaScriptMathieu Breton
 
Functional microscope - Lenses in C++
Functional microscope - Lenses in C++Functional microscope - Lenses in C++
Functional microscope - Lenses in C++Alexander Granin
 
Code as data as code.
Code as data as code.Code as data as code.
Code as data as code.Mike Fogus
 
Oxygine 2 d objects,events,debug and resources
Oxygine 2 d objects,events,debug and resourcesOxygine 2 d objects,events,debug and resources
Oxygine 2 d objects,events,debug and resourcescorehard_by
 
Hacking JavaFX with Groovy, Clojure, Scala, and Visage
Hacking JavaFX with Groovy, Clojure, Scala, and VisageHacking JavaFX with Groovy, Clojure, Scala, and Visage
Hacking JavaFX with Groovy, Clojure, Scala, and VisageStephen Chin
 
夜子まま塾講義3(androidで電卓アプリを作る)
夜子まま塾講義3(androidで電卓アプリを作る)夜子まま塾講義3(androidで電卓アプリを作る)
夜子まま塾講義3(androidで電卓アプリを作る)Masafumi Terazono
 
Stamps - a better way to object composition
Stamps - a better way to object compositionStamps - a better way to object composition
Stamps - a better way to object compositionVasyl Boroviak
 
Advance features of C++
Advance features of C++Advance features of C++
Advance features of C++vidyamittal
 
Better Software: introduction to good code
Better Software: introduction to good codeBetter Software: introduction to good code
Better Software: introduction to good codeGiordano Scalzo
 
The Ring programming language version 1.3 book - Part 37 of 88
The Ring programming language version 1.3 book - Part 37 of 88The Ring programming language version 1.3 book - Part 37 of 88
The Ring programming language version 1.3 book - Part 37 of 88Mahmoud Samir Fayed
 
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...Stephen Chin
 
Functional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonadsFunctional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonadsAlexander Granin
 
Низкоуровневые оптимизации .NET-приложений
Низкоуровневые оптимизации .NET-приложенийНизкоуровневые оптимизации .NET-приложений
Низкоуровневые оптимизации .NET-приложенийAndrey Akinshin
 

Mais procurados (20)

TypeScript - All you ever wanted to know - Tech Talk by Epic Labs
TypeScript - All you ever wanted to know - Tech Talk by Epic LabsTypeScript - All you ever wanted to know - Tech Talk by Epic Labs
TypeScript - All you ever wanted to know - Tech Talk by Epic Labs
 
Clean code in JavaScript
Clean code in JavaScriptClean code in JavaScript
Clean code in JavaScript
 
Python speleology
Python speleologyPython speleology
Python speleology
 
Functional microscope - Lenses in C++
Functional microscope - Lenses in C++Functional microscope - Lenses in C++
Functional microscope - Lenses in C++
 
Code as data as code.
Code as data as code.Code as data as code.
Code as data as code.
 
Oxygine 2 d objects,events,debug and resources
Oxygine 2 d objects,events,debug and resourcesOxygine 2 d objects,events,debug and resources
Oxygine 2 d objects,events,debug and resources
 
Hacking JavaFX with Groovy, Clojure, Scala, and Visage
Hacking JavaFX with Groovy, Clojure, Scala, and VisageHacking JavaFX with Groovy, Clojure, Scala, and Visage
Hacking JavaFX with Groovy, Clojure, Scala, and Visage
 
ES6 Overview
ES6 OverviewES6 Overview
ES6 Overview
 
夜子まま塾講義3(androidで電卓アプリを作る)
夜子まま塾講義3(androidで電卓アプリを作る)夜子まま塾講義3(androidで電卓アプリを作る)
夜子まま塾講義3(androidで電卓アプリを作る)
 
Stamps - a better way to object composition
Stamps - a better way to object compositionStamps - a better way to object composition
Stamps - a better way to object composition
 
Advance features of C++
Advance features of C++Advance features of C++
Advance features of C++
 
Functional Scala 2020
Functional Scala 2020Functional Scala 2020
Functional Scala 2020
 
Better Software: introduction to good code
Better Software: introduction to good codeBetter Software: introduction to good code
Better Software: introduction to good code
 
Scala best practices
Scala best practicesScala best practices
Scala best practices
 
The Ring programming language version 1.3 book - Part 37 of 88
The Ring programming language version 1.3 book - Part 37 of 88The Ring programming language version 1.3 book - Part 37 of 88
The Ring programming language version 1.3 book - Part 37 of 88
 
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...
 
Introduction to Domain-Driven Design
Introduction to Domain-Driven DesignIntroduction to Domain-Driven Design
Introduction to Domain-Driven Design
 
Functional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonadsFunctional "Life": parallel cellular automata and comonads
Functional "Life": parallel cellular automata and comonads
 
Низкоуровневые оптимизации .NET-приложений
Низкоуровневые оптимизации .NET-приложенийНизкоуровневые оптимизации .NET-приложений
Низкоуровневые оптимизации .NET-приложений
 
Academy PRO: ES2015
Academy PRO: ES2015Academy PRO: ES2015
Academy PRO: ES2015
 

Semelhante a JavaTalks: OOD principles

Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code DevelopmentPeter Gfader
 
Imagine a world without mocks
Imagine a world without mocksImagine a world without mocks
Imagine a world without mockskenbot
 
Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015
Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015
Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015NoSQLmatters
 
NoSQL meets Microservices - Michael Hackstein
NoSQL meets Microservices - Michael HacksteinNoSQL meets Microservices - Michael Hackstein
NoSQL meets Microservices - Michael Hacksteindistributed matters
 
JSON SQL Injection and the Lessons Learned
JSON SQL Injection and the Lessons LearnedJSON SQL Injection and the Lessons Learned
JSON SQL Injection and the Lessons LearnedKazuho Oku
 
자바스크립트 비동기 코드(Javascript asyncronous code)
자바스크립트 비동기 코드(Javascript asyncronous code)자바스크립트 비동기 코드(Javascript asyncronous code)
자바스크립트 비동기 코드(Javascript asyncronous code)Kongson Park
 
A miało być tak... bez wycieków
A miało być tak... bez wyciekówA miało być tak... bez wycieków
A miało być tak... bez wyciekówKonrad Kokosa
 
Intravert Server side processing for Cassandra
Intravert Server side processing for CassandraIntravert Server side processing for Cassandra
Intravert Server side processing for CassandraEdward Capriolo
 
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"DataStax Academy
 
Vavr Java User Group Rheinland
Vavr Java User Group RheinlandVavr Java User Group Rheinland
Vavr Java User Group RheinlandDavid Schmitz
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksMongoDB
 
Aprimorando sua Aplicação com Ext JS 4 - BrazilJS
Aprimorando sua Aplicação com Ext JS 4 - BrazilJSAprimorando sua Aplicação com Ext JS 4 - BrazilJS
Aprimorando sua Aplicação com Ext JS 4 - BrazilJSLoiane Groner
 
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...DroidConTLV
 
The State of JavaScript (2015)
The State of JavaScript (2015)The State of JavaScript (2015)
The State of JavaScript (2015)Domenic Denicola
 
A la découverte de TypeScript
A la découverte de TypeScriptA la découverte de TypeScript
A la découverte de TypeScriptDenis Voituron
 
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...Igalia
 
Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#Vagif Abilov
 

Semelhante a JavaTalks: OOD principles (20)

SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code Development
 
Imagine a world without mocks
Imagine a world without mocksImagine a world without mocks
Imagine a world without mocks
 
NoSQL meets Microservices
NoSQL meets MicroservicesNoSQL meets Microservices
NoSQL meets Microservices
 
Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015
Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015
Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015
 
NoSQL meets Microservices - Michael Hackstein
NoSQL meets Microservices - Michael HacksteinNoSQL meets Microservices - Michael Hackstein
NoSQL meets Microservices - Michael Hackstein
 
JSON SQL Injection and the Lessons Learned
JSON SQL Injection and the Lessons LearnedJSON SQL Injection and the Lessons Learned
JSON SQL Injection and the Lessons Learned
 
자바스크립트 비동기 코드(Javascript asyncronous code)
자바스크립트 비동기 코드(Javascript asyncronous code)자바스크립트 비동기 코드(Javascript asyncronous code)
자바스크립트 비동기 코드(Javascript asyncronous code)
 
A miało być tak... bez wycieków
A miało być tak... bez wyciekówA miało być tak... bez wycieków
A miało być tak... bez wycieków
 
Intravert Server side processing for Cassandra
Intravert Server side processing for CassandraIntravert Server side processing for Cassandra
Intravert Server side processing for Cassandra
 
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
 
mobl
moblmobl
mobl
 
Vavr Java User Group Rheinland
Vavr Java User Group RheinlandVavr Java User Group Rheinland
Vavr Java User Group Rheinland
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
 
Aprimorando sua Aplicação com Ext JS 4 - BrazilJS
Aprimorando sua Aplicação com Ext JS 4 - BrazilJSAprimorando sua Aplicação com Ext JS 4 - BrazilJS
Aprimorando sua Aplicação com Ext JS 4 - BrazilJS
 
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
 
The State of JavaScript (2015)
The State of JavaScript (2015)The State of JavaScript (2015)
The State of JavaScript (2015)
 
A la découverte de TypeScript
A la découverte de TypeScriptA la découverte de TypeScript
A la découverte de TypeScript
 
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
 
Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#
 

Último

🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 

Último (20)

🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 

JavaTalks: OOD principles

  • 2. 2 План презентации • Intro • Don’t Repeat Yourself • Open Closed • Single Responsibility • Interface Segregation • Inversion of Control • Liskov’s Substitution • Q/A
  • 3. 3 OOD Principles. What’s that? • Recipes, best practices how to write • Clean, easy to understand code • Maintainable (flexible, extendable) code
  • 4. DRY Don’t Repeat Yourself • Don’t duplicate code
  • 5. 5 Without DRY st.executeQuery("select user.name, user.password from user where id=?");
  • 6. If something changes? st.executeQuery("select user.username, user.password from user where id=?");
  • 7. With DRY st.executeQuery("select user.name, user.password from user where id=?"); public User getUser(Long id) {…}
  • 8. If something changes? st.executeQuery("select user.username, user.password from user where id=?"); public User getUser(Long id) {…}
  • 9. DRY Don’t Repeat Yourself • Don’t duplicate code • Names should be clear
  • 10. Not clear names public class Utils { public static Connection createConnection(String... params){...} public static Object[] getSortedArray(Object[] array){...} } 1. No one would guess to look sorting method in this class. 2. Newbie always would write his own implementation.
  • 11. Correct DRY public class ArrayUtils { public static Object[] getSortedArray(Object[] array) {…} } public class DatabaseUtils { public static Connection createConnection(String... params) {...} } clear, well-defined class names
  • 12. DRY Don’t Repeat Yourself • Don’t duplicate code • Names should be clear • Location should be clear
  • 13. Not clear location package ru.jt.transformer.csv; public class ArrayUtils { public static Object[] getSortedArray(Object[] array) {...} } No one would look for array utilities in such package
  • 14. DRY. Pros & Cons Pros: • Changes impact local area • Once written is not repeated • No ”new” error prone solutions Cons: • Amount of classes grows
  • 15. OCP Open Closed Principle - code should be closed for modification, but open for extension.
  • 16. OCP. Example I want my clients to be able to see results of past games. Let’s keep up with NHL & NBA games.. 1. American customer 2. His thoughts 3. His ill imagination
  • 17. OCP. Example public class SportInfoParser implements SportInfoParser { public SportInfo parseSportInfo(String[] sportInfoArray) { SportInfo sportInfo = null; if ("nba".equals(sportInfoArray[0])) { NbaSportInfo nbaSportInfo = new NbaSportInfo(); Map<Long, Integer> scores = new HashMap<Long, Integer>(); scores.put(Long.parseLong(sportInfoArray[12]), Integer.parseInt(sportInfoArray[13])); nbaSportInfo.setScores(scores); sportInfo = nbaSportInfo; } else if ("nhl".equals(sportInfoArray[0])) { NhlSportInfo nhlSportInfo = new NhlSportInfo(); nhlSportInfo.setSlapShotCount(1); } return sportInfo; } } Base class Creates specific objects according to...
  • 18. OCP. Example Great! A lot of new clients, a lot of money from ads. But.. Would be great if my cliends would be able to get info about MLB games too!
  • 19. OCP. Example public class SportInfoParser implements SportInfoParser { public SportInfo parseSportInfo(String[] sportInfoArray) { SportInfo sportInfo = null; if ("nba".equalsIgnoreCase(sportInfoArray[0])) { NbaSportInfo nbaSportInfo = new NbaSportInfo(); Map<Long, Integer> scores = new HashMap<Long, Integer>(); scores.put(Long.parseLong(sportInfoArray[12]), Integer.parseInt(sportInfoArray[13])); nbaSportInfo.setScores(scores); sportInfo = nbaSportInfo; } else if ("nhl".equalsIgnoreCase(sportInfoArray[0])) { NhlSportInfo nhlSportInfo = new NhlSportInfo(); nhlSportInfo.setSlapShotCount(1); } else if(sportInfoArray[0].equalsIgnoreCase("mlb")){ MlbSportInfo mlbSportInfo = new MlbSportInfo(); mlbSportInfo.setHits(Integer.parseInt(sportInfoArray[1])); mlbSportInfo.setRuns(Integer.parseInt(sportInfoArray[2])); } return sportInfo; } } New league was added We are changing already working class!
  • 20. OCP. Example Why my clients see errors on every page?!! I pay you for work, not for errors! I loose my clients, make the program work right!
  • 21. OCP. Example public class SportInfoParser implements SportInfoParser { public SportInfo parseSportInfo(String[] sportInfoArray) { SportInfo sportInfo = null; if ("nba".equalsIgnoreCase(sportInfoArray[0])) { NbaSportInfo nbaSportInfo = new NbaSportInfo(); Map<Long, Integer> scores = new HashMap<Long, Integer>(); scores.put(Long.parseLong(sportInfoArray[12]), Integer.parseInt(sportInfoArray[13])); nbaSportInfo.setScores(scores); sportInfo = nbaSportInfo; } else if ("nhl".equalsIgnoreCase(sportInfoArray[0])) { NhlSportInfo nhlSportInfo = new NhlSportInfo(); nhlSportInfo.setSlapShotCount(1); } else if(sportInfoArray[0].equalsIgnoreCase("mlb")){ MlbSportInfo mlbSportInfo = new MlbSportInfo(); mlbSportInfo.setHits(Integer.parseInt(sportInfoArray[1])); mlbSportInfo.setRuns(Integer.parseInt(sportInfoArray[2])); } return sportInfo; } } Element of array is compared with league name – NPE is possible!
  • 22. OCP. Moral This example shows that changing code that already works is always bad idea. Follow OCP to escape this!
  • 23. OCP. Example public class SportInfoParser implements SportInfoParser { private Map<String, SportInfoBuilder> builders; public SportInfoParserEnhanced(Map<String, SportInfoBuilder> builders) { this.builders = builders; } public SportInfo parseSportInfo(String[] sportInfoArray) { SportInfoBuilder builder = builders.get(sportInfoArray[0]); if(builder != null){ return builder.build(sportInfoArray); } return null; } } MlbSportInfoBuilder NbaSportInfoBuilder NhlSportInfoBuilder public class NbaSportInfoBuilder implements SportInfoBuilder { public SportInfo build(String[] sportInfoArray) { NbaSportInfo nbaSportInfo = new NbaSportInfo(); Map<Long, Integer> scores = new HashMap<Long, Integer>(); scores.put(…, …); nbaSportInfo.setScores(scores); return nbaSportInfo; } }
  • 24. OCP. Example Great! You job satisfies me! But now I want WNBA to be added 
  • 25. OCP. Example public class SportInfoParser implements SportInfoParser { private Map<String, SportInfoBuilder> builders; public SportInfoParserEnhanced(Map<String, SportInfoBuilder> builders) { this.builders = builders; } public SportInfo parseSportInfo(String[] sportInfoArray) { SportInfoBuilder builder = builders.get(sportInfoArray[0]); if(builder != null){ return builder.build(sportInfoArray); } return null; } } MlbSportInfoBuilder NbaSportInfoBuilder NhlSportInfoBuilder WnbaSportInfoBuilder New league was added without changing single line of code!
  • 26. OCP. How it works OCP uses: • Delegation • Inheritance
  • 27. OCP. Pros & Cons Pros: • Adding new functionality without legacy code being changed Cons: • May complicate system because of amount of classes being grown
  • 28. SRP Single Responsibility Principle: • Single class should have a single responsibility • Class should have only one reason to change
  • 29. SRP. Random thoughts public class CurrencyConverter { public BigDecimal convert(Currency from, Currency to, BigDecimal amount) { // gets connection to some online service and asks it to convert currency // parses the answer and returns results } public BigDecimal getInflationIndex(Currency currency, Date from, Date to) { // gets connection to some online service to get data about // currency inflation for specified period } } Hm.. Strange that inflation is counted in CurrencyConverter.. Hm.. What if format of currency service changes? What if the format of inflation service changes? We’ll have to change this class in both cases! It’s not intuitive! It’s overloaded! We have to do something!
  • 30. SRP. Separate Responsibilities public class CurrencyConverter { public BigDecimal convert(Currency from, Currency to, BigDecimal amount) { // gets connection to some online service and asks it to convert currency // parses the answer and returns results } } public class InflationIndexCounter { public BigDecimal getInflationIndex(Currency currency, Date from, Date to) { // gets connection to some online service to get data about // currency inflation for specified period } } Hm.. What if format of currency service changes? We change CurrencyConverter! Hm.. What if format of inflation service changes? We change InflationIndexCounter!
  • 31. SRP & DRY Again two responsibilities: Authentication & getting user from database public class UserAuthenticator { public boolean authenticate(String username, String password){ User user = getUser(username); return user.getPassword().equals(password); } private User getUser(String username){ st.executeQuery("select user.name, user.password from user where id=?"); // something's here return user; } } DRY violation!
  • 32. SRP. Delegating responsibilities public class UserAuthenticator { private UserDetailsService userDetailsService; public UserAuthenticator(UserDetailsService service) { userDetailsService = service; } public boolean authenticate(String username, String password){ User user = userDetailsService.getUser(username); return user.getPassword().equals(password); } } Now we don’t work directly with database! If we would want to use ORM, UserAuthenticator won’t change!
  • 33. SRP. Pros & Cons Pros: • Helps to follow DRY • Lowers chances to change single class • Class names correspond to what they do Cons: • May complecate system by adding too much new classes
  • 34. ISP Interface Segregation Principle – client code shouldn’t be obligated to depend on interfaces it doesn’t use.
  • 35. ISP. Example interface Person { void goToWork(); void withdrawSalary(); void eat(); } Base interface of the person. All these methods are useful for current implementation of person.
  • 36. ISP. Extra methods interface Person { void goToWork(); void withdrawSalary(); void eat(); } But we’re writting new module that considers a person only as a human being. So we need only one method eat() public class PersonImpl implements Person { public void goToWork() { throw new UnsupportedOperationException(); } public void withdrawSalary() { throw new UnsupportedOperationException(); } public void eat() { //some real implementation } } So our new implementation has two extra methods.
  • 37. ISP. What these methods do?!
  • 38. ISP. Fat/Polluted Interfaces interface Person { void goToWork(); void withdrawSalary(); void eat(); } It’s fat It’s POLLUTED
  • 39. ISP. Interface Separating public interface Person { void eat(); } public interface Worker { void goToWork(); void withdrawSalary(); } We separated Person into Person & Worker. Two conceptually different interfaces.
  • 40. ISP. No extra methods public class PersonImpl implements Person { public void eat() { //some real implementation } } Now we have only needed methods.
  • 41. ISP. Legacy code What if we have ready implementation, but we don’t want to use fat interface? public class FatPersonImpl implements FatPerson { public void goToWork() { //some real implementation } public void withdrawSalary() { //some real implementation } public void eat() { //some real implementation } }
  • 42. ISP. Use Adapters public class PersonAdapter implements Person { private FatPerson fatPerson; public PersonAdapter(FatPerson fatPerson) { this.fatPerson = fatPerson; } public void eat() { fatPerson.eat(); } } Thin interface Fat interface
  • 43. ISP. Pros & Cons Pros: • No need to implement unnecessary methods • Client code sees only what it should see Cons: • Adding additional interfaces
  • 44. IoCP Invertion of Control Principle says: • Code to abstraction, not to implementation • Objects that use other objects, shouldn’t create latter ones
  • 45. IoCP. Coding to implementation public interface HtmlParser { HtmlDocument parseUrl(String url); } public class Crawler { public void saveHtmlDocument() { DomBasedHtmlParser parser = new DomBasedHtmlParser(); HtmlDocument document = parser.parseUrl("http://javatalks.ru"); save(document, "jt-index"); } public void save(HtmlDocument htmlDocument, String pageName) { // logic of saving } } public class DomBasedHtmlParser implements HtmlParser { public HtmlDocument parseUrl(String url) { // getting html page as stream //parsing it with DOM parser //creating HtmlDocument return htmlDocuments; } }
  • 46. IoCP. How to test Crawler? public class Crawler { public void saveHtmlDocument() { DomBasedHtmlParser parser = new DomBasedHtmlParser(); HtmlDocument document = parser.parseUrl("http://javatalks.ru"); save(document, "jt-index"); } public void save(HtmlDocument htmlDocument, String pageName) { // logic of saving } } It’s impossible to write unit test for Crawler, because you cannot mock parser.
  • 47. IoCP. Let’s inject public class Crawler { private DomBasedHtmlParser parser; public Crawler(DomBasedHtmlParser parser) { this.parser = parser; } public void saveHtmlDocument() { HtmlDocument document = parser.parseUrl("http://javatalks.ru"); save(document, "jt-index"); } public void save(HtmlDocument htmlDocument, String pageName) { // logic of saving } } Crawler crawler = new Crawler(someMockParser); Now you can specify parser through constructor. You can inject dummy object while testing.
  • 48. IoCP. Again doesn’t work Your parser doesn’t work with HTML that isn’t a valid XML!
  • 50. IoCP. But how do we replace? public class Crawler { private DomBasedHtmlParser parser; public Crawler(DomBasedHtmlParser parser) { this.parser = parser; } public void saveHtmlDocument() { HtmlDocument document = parser.parseUrl("http://javatalks.ru"); save(document, "jt-index"); } public void save(HtmlDocument htmlDocument, String pageName) { // logic of saving } }We cannot specify another implementaion!
  • 51. IoCP. Let’s code to interface public class Crawler { private HtmlParser parser; public Crawler(HtmlParser parser) { this.parser = parser; } public void saveHtmlDocument() { HtmlDocument document = parser.parseUrl("http://javatalks.ru"); save(document, "jt-index"); } public void save(HtmlDocument htmlDocument, String pageName) { // logic of saving } } Now we use interface, so we can specify enhanced implementation of parser.
  • 52. IoCP. Another look How do we inject objects if we work on framework/library? We cannot use IoC Containers, our clients don’t allow us extra dependencies, they don’t want to depend on Spring or Guice. We need leightweight decision.
  • 53. IoCP. Let’s use Factories public class Crawler{ private HtmlParser parser = ParserFactory.getHtmlParser(); public void saveHtmlDocument() { HtmlDocument document = parser.parseUrl("http://javatalks.ru"); save(document, "jt-index"); } } Let’s use Factories! Hm.. But we cannot write unit tests again!
  • 54. IoCP. Let’s mix public class Crawler{ private HtmlParser parser = ParserFactory.getHtmlParser(); public void saveHtmlDocument() { HtmlDocument document = parser.parseUrl("http://javatalks.ru"); save(document, "jt-index"); } public void setParser(HtmlParser parser) { this.parser = parser; } } We have both: setter and factory in the same class. Now we have default implementation and possibility to change default behavior.
  • 55. IoCP. Pros & Cons Pros: • Classes don’t depend on concrete implementation • Allows easily change implementation • Allows write good unit tests Cons: • Creating additional interfaces • Creating Factories/depending on IoC containers
  • 56. LSP Liskov’s Substitution Principle – derived types must be completely substitutable for their base types. LSP declares how to use inheritance correctly.
  • 57. LSP. java.util.List List list = new ArrayList(); List list = new LinkedList(); list.get(1); Would be strange if these implementation would do different things here
  • 58. LSP. Emu doesn’t fly! class Bird extends Animal { @Override //walk is overriden from Animal public void walk() {...} @Override //makeOffspring() is overriden from Animal public void makeOffspring() {...}; //was added public void fly() {...} } class Emu extend Bird { public void makeOffspring() {...} } But emu doesn’t fly!
  • 59. LSP. Emu indeed doesn’t fly class Bird extends Animal { @Override //walk is overriden from Animal public void walk() {...} @Override //makeOffspring() is overriden from Animal public void makeOffspring() {...} } class FlyingBird extends Bird { public void fly() {...} } class Emu extends Bird { @Override public void makeOffspring(){..} } Simply birds. Flying birds. Emu is simply a bird. It doesn’t have extra methods.
  • 60. LSP. Array example interface ArraySorter { Object[] parse(Object []args); } class DefaultArraySorter implements ArraySorter { public Object[] sort(Object []array){ Object[] result = array.clone(); ... } } Default implementation. It’s a temporal class that uses unefficient approach. But it does it’s work correctly.
  • 61. LSP. Array example interface ArraySorter { Object[] parse(Object []args); } At last we wrote enhanced implementation that’s really efficient. class QuickArraySorter implements ArraySorter { public Object[] sort(Object []array){ Object[] result = array; ... } }
  • 62. LSP. Again bugs! Your system always throws errors! It’s a chaos!!
  • 63. LSP. Array example class QuickArraySorter implements ArraySorter { public Object[] sort(Object []array){ Object[] result = array; ... } } It sorts the original array! We have problems with synchronization. Implementation does its work, but it has side effects. It doesn’t satisfy interface contract! We cannot simply replace one implementation with another one, because they differ! We should correct its behaviour to copy original array and work with its copy.
  • 64. LSP & equals() public class Point { private int x; private int y; @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Point)) return false; Point point = (Point) o; if (x != point.x) return false; if (y != point.y) return false; return true; } } public class ColoredPoint extends Point { private int color; @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ColoredPoint)) return false; if (!super.equals(o)) return false; ColoredPoint that = (ColoredPoint) o; if (color != that.color) return false; return true; } } Colored point extends simple point and adds new field – color. But it works only with ColoredPoint!
  • 65. LSP & equals Point point = new Point(1, 1); ColoredPoint coloredPoint = new ColoredPoint(1, 1, 1); System.out.println(point.equals(coloredPoint)); System.out.println(coloredPoint.equals(point)); This will print: true false This violates equals() contract! There is no correct dicision in this situation!
  • 66. LSP & equals() public class ColoredPoint { private Point point; private int color; } The only correct way here is to use delegation instead of inheritance.
  • 67. LSP & exceptions List list = new OurSuperPuperImplementation(); list.iterator().next(); What if this method in our implementation threw IOException? How would we know about that? We work with interface List, not with implementation! That’s why Java doesn’t allow us to throw any checked exception that are not declared in base class.
  • 68. LSP. Pros & Cons Pros: • Allows not to think about concrete implementation, but code to abstraction • Unambiguously defines contract all implementers should follow • Allows to interchange implementation correctly, without side effects