Top Banner
Башкирцев (Старовер) Станислав [email protected] JavaTalks OOD Principles
69
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

Башкирцев (Старовер) Станислав[email protected]

OOD Principles

Page 2: Башкирцев (Старовер) Станислав 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

Page 3: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

3

OOD Principles. What’s that?

• Recipes, best practices how to write• Clean, easy to understand code

• Maintainable (flexible, extendable) code

Page 4: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

DRY

Don’t Repeat Yourself• Don’t duplicate code

Page 5: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

5

Without DRY

st.executeQuery("select user.name, user.password from user where id=?");

Page 6: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

If something changes?

st.executeQuery("select user.username, user.password from user where id=?");

Page 7: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

With DRY

st.executeQuery("select user.name, user.password from user where id=?");

public User getUser(Long id) {…}

Page 8: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

If something changes?

st.executeQuery("select user.username, user.password from user where id=?");

public User getUser(Long id) {…}

Page 9: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

DRY

Don’t Repeat Yourself• Don’t duplicate code

• Names should be clear

Page 10: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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.

Page 11: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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

Page 12: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

DRY

Don’t Repeat Yourself• Don’t duplicate code

• Names should be clear

• Location should be clear

Page 13: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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

Page 14: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

DRY. Pros & Cons

Pros:

• Changes impact local area

• Once written is not repeated

• No ”new” error prone solutions

Cons:

• Amount of classes grows

Page 15: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

OCP

Open Closed Principle - code should be closed for modification, but open for extension.

Page 16: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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

Page 17: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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...

Page 18: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 19: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 20: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 21: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 22: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

OCP. Moral

This example shows that changing code that already works is always bad idea.

Follow OCP to escape this!

Page 23: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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; } }

Page 24: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

OCP. Example

Great! You job satisfies me!But now I want WNBA to be

added

Page 25: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 26: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

OCP. How it works

OCP uses:• Delegation

• Inheritance

Page 27: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

OCP. Pros & Cons

Pros:

• Adding new functionality without legacy code being changed

Cons:

• May complicate system because of amount of classes being grown

Page 28: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

SRP

Single Responsibility Principle:

• Single class should have a single responsibility

• Class should have only one reason to change

Page 29: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 30: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 31: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 32: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 33: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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

Page 34: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

ISP

Interface Segregation Principle – client code shouldn’t be obligated to depend on interfaces it doesn’t use.

Page 35: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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.

Page 36: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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.

Page 37: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

ISP. What these methods do?!

Page 38: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

ISP. Fat/Polluted Interfaces

interface Person { void goToWork(); void withdrawSalary(); void eat(); }

It’s fat

It’s POLLUTED

Page 39: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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.

Page 40: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

ISP. No extra methods

public class PersonImpl implements Person { public void eat() { //some real implementation } }

Now we have only needed methods.

Page 41: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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 } }

Page 42: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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

Page 43: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

ISP. Pros & Cons

Pros:

• No need to implement unnecessary methods

• Client code sees only what it should see

Cons:

• Adding additional interfaces

Page 44: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

IoCP

Invertion of Control Principle says:

• Code to abstraction, not to implementation

• Objects that use other objects, shouldn’t create latter ones

Page 45: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

IoCP. Coding to implementationpublic 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; } }

Page 46: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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.

Page 47: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

IoCP. Let’s injectpublic 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.

Page 48: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

IoCP. Again doesn’t work

Your parser doesn’t work with HTML that

isn’t a valid XML!

Page 49: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

IoCP. New Implementation

HtmlParser

DomBasedHtmlParser

EnhancedHtmlParser

Page 50: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 51: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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.

Page 52: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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.

Page 53: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 54: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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.

Page 55: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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

Page 56: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

LSP

Liskov’s Substitution Principle – derived types must be completely substitutable for their base types.

LSP declares how to use inheritance correctly.

Page 57: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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

Page 58: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 59: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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.

Page 60: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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.

Page 61: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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; ... } }

Page 62: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

LSP. Again bugs!

Your system always throws errors! It’s a

chaos!!

Page 63: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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.

Page 64: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 65: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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!

Page 66: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

LSP & equals()

public class ColoredPoint { private Point point; private int color; }

The only correct way here is to use delegation

instead of inheritance.

Page 67: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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.

Page 68: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

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

Page 69: Башкирцев (Старовер) Станислав ctapobep@javatalks.ru JavaTalks OOD Principles.

The End

Q/A