OO Design Principles & Metrics

  • Upload
    knslf

  • View
    220

  • Download
    0

Embed Size (px)

Citation preview

  • 8/13/2019 OO Design Principles & Metrics

    1/44

  • 8/13/2019 OO Design Principles & Metrics

    2/44

    Jason Gorman 2006

    www.parlezuml.com

    OO Design Goals

    Make software easier to change when we wantto

    We might wantto change a class or package to add new

    functionality, change business rules or improve the design

    We might have to change a class or package because of a

    change to another class or package it depends on (e.g., a

    change to a method signature) Manage dependencies between classes and packages of

    classes to minimise impact of change on other parts of the

    software

    Minimise reasons that modules or packages might be forced tochange because of a change in a module or package it depends

    upon

  • 8/13/2019 OO Design Principles & Metrics

    3/44

    Jason Gorman 2006

    www.parlezuml.com

    Cat Poetry

    Cat Poetry

    Cat Poetry Between Well-defined Interfaces

  • 8/13/2019 OO Design Principles & Metrics

    4/44

    Jason Gorman 2006

    www.parlezuml.com

    A Hazelnut In Every Bite

    Much of OO design is about managing

    dependencies It is very difficult to write OO code without

    creating a dependency on something => 99.9% of lines of code contain at least

    one significant design decision

    => Anyone who writes a line of code is

    defining the design

  • 8/13/2019 OO Design Principles & Metrics

    5/44

    Jason Gorman 2006

    www.parlezuml.com

    Every Programmer Is ADesigner!

  • 8/13/2019 OO Design Principles & Metrics

    6/44

    Jason Gorman 2006

    www.parlezuml.com

    Class Design

    Class Cohesion

    Open-Closed Single Responsibility

    Interface Segregation Dependency Inversion

    Liskov Substitution

    Law of Demeter

    Reused Abstractions

  • 8/13/2019 OO Design Principles & Metrics

    7/44

    Jason Gorman 2006

    www.parlezuml.com

    Class CohesionReasoning:Class design should reduce the need to edit multiple classes when making changes to application logic. A

    fundamental goal of OO design is to place the behaviour (methods) as close to the data they operate on

    (attributes) as possible, so that changes are less likely to propagate across multiple classes

    Account

    balance : Real

    setBalance(amount : Real)

    getBalance() : Real

    Withdraw alTx

    amount : Real

    execute()

    DepositTx

    amount : Real

    execute()

    1 *

    1

    *

    TransferTx

    amount : Real

    execute()

    1

    payer

    payee

    oldBalance = account.getBalance()

    If(amount > 0) {

    account.setBalance(oldBalance +

    amount);

    }

    oldBalance = account.getBalance();

    If(amount > 0 && amount >= oldBalance) {

    account.setBalance(oldBalance -

    amount);

    }

    payeeBalance = payee.getBalance();

    payerBalance = payer.getBalance();

    If(amount > 0 && amount >= payerBalance) {payer.setBalance(payerBalance -

    amount);

    payee.setBalance(payeeBalance +

    amount);

    }

  • 8/13/2019 OO Design Principles & Metrics

    8/44

    Jason Gorman 2006

    www.parlezuml.com

    Class Cohesion - RefactoredReasoning:Class design should reduce the need to edit multiple classes when making changes to application logic. A

    fundamental goal of OO design is to place the behaviour (methods) as close to the data they operate on

    (attributes), so that changes are less likely to propagate across multiple classes

    Account

    balance : Real

    withdraw(amount : Real)

    deposit(amount : Real)

    getBalance() : Real

    Withdraw alTx

    amount : Real

    execute()

    DepositTx

    amount : Real

    execute()

    1 *

    1

    *

    TransferTx

    amount : Real

    execute()

    1

    payer

    payee

    account.deposit(amount)

    account.withdraw(amount)

    payer.withdraw(amount)payee.deposit(amount)

  • 8/13/2019 OO Design Principles & Metrics

    9/44

    Jason Gorman 2006

    www.parlezuml.com

    Class Cohesion Metrics

    Lack of Cohesion of Methods (LCOM) = ((D R(A))/A) - M

    A1

    A2

    A3

    A4

    Class has A attributes

    M1

    M2

    M3

    M4

    Class has M methods

    Each attribute A is

    accessed by R(A)

    methods1 M

    automation possible

    The average number of methods that

    access each attribute

    TIP: An reference to an associated object is equivalent to anattribute

  • 8/13/2019 OO Design Principles & Metrics

    10/44

    Jason Gorman 2006

    www.parlezuml.com

    Open-Closed

    Reasoning:Once a class is tested and working, modifying its code can introduce new bugs. We avoid

    this by extending the class, leaving its code unchanged, to add new behaviour.

    Classes should be open to extension, but closed to modification

    Account

    isSettlementAccount : Booleanbalance : Real

    debt : Real

    getAvailableFunds()

    Pseudo-code:

    float getAvailableFunds() {

    if isSettlementAccount then

    return balance debt

    else

    return balance

    }

    Account

    balance : Real

    getAvailableFunds()

    Pseudo-code:

    float getAvailableFunds() {

    return balance

    }

    modifiedmodified

  • 8/13/2019 OO Design Principles & Metrics

    11/44

    Jason Gorman 2006

    www.parlezuml.com

    Open-Closed - Refactored

    Reasoning:Once a class is tested and working, modifying its code can introduce new bugs. We avoid

    this by extending the class, leaving its code unchanged, to add new behaviour. Classes

    should be open to extension, but closed to modification

    Account

    balance : Real

    getAvailableFunds()

    Pseudo-code:

    //overrides

    float getAvailableFunds() {

    return base.getAvailableFunds() debt}

    Account

    balance : Real

    getAvailableFunds()

    Pseudo-code:

    float getAvailableFunds() {

    return balance

    }

    extendedextended

    SettlementAccount

    debt : Real

    getAvailableFunds()

  • 8/13/2019 OO Design Principles & Metrics

    12/44

    Jason Gorman 2006

    www.parlezuml.com

    automation possible

    Open-Closed - Metrics

    Per successful check-in

    classes extended and not modified / classes extended and/or modified

    Account

    isSettlementAccount : Booleanbalance : Real

    debt : Real

    getAvailableFunds()

    Pseudo-code:

    float getAvailableFunds() {

    if isSettlementAccount then

    return balance debt

    else

    return balance

    }

    Account

    balance : Real

    getAvailableFunds()

    Pseudo-code:

    float getAvailableFunds() {

    return balance

    }

    modifiedmodified

  • 8/13/2019 OO Design Principles & Metrics

    13/44

    Jason Gorman 2006

    www.parlezuml.com

    Single Responsibility

    Account

    balance : Real

    deposit(amount : Real)withdraw(amount : Real)getBalance() : Real

    toXml() : String

    Responsibilities:

    model bank account serialise account to XML string

    Two reasons why this class might need to change

    changes to domain logic

    changes to XML format

    Reasoning:Changing code in a tested class can introduce new bugs. We seek to minimise

    the reasons why a class might need to change. The more different things a

    class does, the more reasons it might have to change.

  • 8/13/2019 OO Design Principles & Metrics

    14/44

    Jason Gorman 2006

    www.parlezuml.com

    Single Responsibility - Refactored

    Account

    balance : Real

    deposit(amount : Real)withdraw(amount : Real)

    getBalance() : Real

    Responsibilities:

    model bank account

    AccountXmlSerializer

    toXml() : String

    1 0..1

    Responsibilities:

    serialise account to XML string

  • 8/13/2019 OO Design Principles & Metrics

    15/44

    Jason Gorman 2006

    www.parlezuml.com

    Single Responsibility - Metrics

    Account

    balance : Real

    deposit(amount : Real)withdraw(amount : Real)getBalance() : Real

    toXml() : String

    Responsibilities:

    model bank account serialise account to XML string

    => responsibilities / class

    by code/design inspection &

    statistical sample

    Q: What is a responsibility?

  • 8/13/2019 OO Design Principles & Metrics

    16/44

    Jason Gorman 2006

    www.parlezuml.com

    Interface Segregation

    Account

    balance : Real

    deposit(amount : Real)withdraw(amount : Real)

    getBalance() : Real

    toXml() : String

    fromXml(xml : String)

    Reasoning:If different clients depend on different methods of the same class, then a change to one

    method might require a recompile and redeployment of other clients who use different

    methods. Creating several client-specific interfaces, one for each type of client, with the

    methods that type of client requires, reduces this problem significantly.

    FundsTransfer

    amount : Real

    execute()

    1

    1

    payer

    payee

    *

    *

    BankingWebService

    1

    *

    Uses:

    deposit()withdraw()

    getBalance()

    Uses:

    toXml()

    fromXml()

  • 8/13/2019 OO Design Principles & Metrics

    17/44

    Jason Gorman 2006

    www.parlezuml.com

    Interface Segregation - Refactored

    Account

    balance : Real

    deposit(amount : Real)withdraw(amount : Real)

    getBalance() : RealtoXml() : String

    fromXml(xml : String)

    FundsTransfer

    amount : Real

    execute()

    BankingWebService

    IAccount

    deposit(amount : Real)

    withdraw(amount : Real)getBalance() : Real

    1 payer

    1

    payee

    *

    *

    IXmlSerializer

    toXml() : String

    fromXml(xml : String)

    1

    *

  • 8/13/2019 OO Design Principles & Metrics

    18/44

    Jason Gorman 2006

    www.parlezuml.com

    Interface Segregation - Metrics

    Account

    balance : Real

    deposit(amount : Real)withdraw(amount : Real)

    getBalance() : Real

    toXml() : String

    fromXml(xml : String)

    FundsTransfer

    amount : Real

    execute()

    1

    1

    payer

    payee

    *

    *

    BankingWebService

    1

    *

    Uses:

    deposit()withdraw()

    getBalance()

    Uses:

    toXml()

    fromXml()

    If type T exposes N methods, and client C uses n of them, then Ts interface is n/N

    specific with respect to C.

    => Average n/N for all clients of T

    automation possible

  • 8/13/2019 OO Design Principles & Metrics

    19/44

    Jason Gorman 2006

    www.parlezuml.com

    Dependency Inversion

    Reasoning:Much of the duplication in code comes f rom client objects know ing about all sorts of specialised suppliers, that

    from the clients perspective do similar things but in dif ferent w ays. Polymorphism is a pow erful mechanism

    that underpins OO design. It allow s us to bind to an abstraction, and then w e dont need to know what concrete

    classes we are collaborating w ith. This makes it much easier to plug in new components w ith no need to

    change the client code.

    UndoCommand

    execute()

    RedoCommand

    execute()

    EditCommand

    execute()

    Application

    EDIT : Integer = 1

    UNDO : Integer = 2

    REDO : Integer = 3

    doAction(actionKind : Integer)

    1

    1

    1

    Pseudo-code:

    void doAction(int actionKind) {

    switch actionKind {

    case EDIT:editCommand.execute()

    case UNDO:

    undoCommand.execute()

    case REDO:

    redoCommand.execute()

    }}

  • 8/13/2019 OO Design Principles & Metrics

    20/44

    Jason Gorman 2006

    www.parlezuml.com

    Dependency Inversion - Refactored

    UndoCommand

    execute()

    RedoCommand

    execute()

    EditCommand

    execute()

    Application

    doAction(actionKind : Integer)

    Pseudo-code:

    void doAction(int index) {

    commands[index].execute()}

    Command

    execute()

    *commands

    {ordered}

  • 8/13/2019 OO Design Principles & Metrics

    21/44

    Jason Gorman 2006

    www.parlezuml.com

    Dependency Inversion - Metrics

    => dependencies on abstractions / total dependencies

    UndoCommand

    execute()

    RedoCommand

    execute()

    EditCommand

    execute()

    Application

    EDIT : Integer = 1

    UNDO : Integer = 2

    REDO : Integer = 3

    doAction(actionKind : Integer)

    1

    1

    1

    Pseudo-code:

    void doAction(int actionKind) {

    switch actionKind {

    case EDIT:editCommand.execute()

    case UNDO:

    undoCommand.execute()

    case REDO:

    redoCommand.execute()

    }}

    automation possible

  • 8/13/2019 OO Design Principles & Metrics

    22/44

    Jason Gorman 2006

    www.parlezuml.com

    Liskov Substitution

    Reasoning:Dynamic polymorphism is a pow erful mechanism that allow s us to invert dependencies, reducing duplication

    and making change much easier. All OO design principles depend upon polymorphism, but w e must ensurethat any type can be substituted for any of its subtypes at run-time w ithout having any adverse effect on the

    client. Subtypes must obey all of the rules that apply to their super-types pre-conditions for calling methods,post-conditions of methods called, and invariants that always apply betw een method calls.

    Account

    balance : Real

    withdraw(amount : Real)

    SettlementAccount

    debt : Real

    context Account::withdraw(amount : Real)

    pre: balance >= amount

    withdraw(amount : Real)

    context SettlementAccount::withdraw(amount : Real )

    pre: balance - debt >= amount

    FundsTransfer

    amount : Real

    execute()

    1

    1

    payer

    payee

    *

    *

    Pseudo code:

    void execute() {

    If payer.getBalance() > amount then

    payer.withdraw(amount)

    payee.deposit(amount)

    elsealert(Payer has insufficient funds)

    }client unwittingly

    breaks pre-condition!!!

  • 8/13/2019 OO Design Principles & Metrics

    23/44

    Jason Gorman 2006

    www.parlezuml.com

    Liskov Substitution - Refactored

    Account

    balance : Real

    / availableFunds = balance

    withdraw(amount : Real)

    SettlementAccount

    debt : Real/ availableFunds = balance - debt

    context Account::withdraw(amount : Real)

    pre: availableFunds >= amount

    withdraw(amount : Real)

    FundsTransfer

    amount : Real

    execute()

    1

    1

    payer

    payee

    *

    *

    Pseudo code:

    void execute() {

    If payer.getAvailableFunds() > amount then

    payer.withdraw(amount)

    payee.deposit(amount)

    elsealert(Payer has insufficient funds)

    }

    pre-condition holdspre-condition holds

    S

  • 8/13/2019 OO Design Principles & Metrics

    24/44

    Jason Gorman 2006

    www.parlezuml.com

    by code/design inspection &

    statistical sample

    Liskov Substitution - Metrics

    Account

    balance : Real

    withdraw(amount : Real)

    SettlementAccount

    debt : Real

    context Account::withdraw(amount : Real)

    pre: balance >= amount

    withdraw(amount : Real)

    context SettlementAccount::withdraw(amount : Real )

    pre: balance - debt >= amount

    FundsTransfer

    amount : Real

    execute()

    1

    1

    payer

    payee

    *

    *

    Pseudo code:

    void execute() {

    If payer.getBalance() > amount then

    payer.withdraw(amount)

    payee.deposit(amount)

    elsealert(Payer has insufficient funds)

    }

    => every class should pass all of the unit tests for all of its super-types

    L f D t

  • 8/13/2019 OO Design Principles & Metrics

    25/44

    Jason Gorman 2006

    www.parlezuml.com

    Law of Demeter

    Reasoning:Objects should only collaborate with their nearest neighbours the less they depend on the

    interfaces of friends of a friend, the less reasons they might have to have to change. This

    means avoiding long navigations and deferring knowledge of interactions with objects that

    arent directly related to your nearest neighbours.

    FundsTransfer

    amount : Real

    execute(amount : Real)

    Account Customerpayee

    1 1

    holder

    **

    Pseudo code:

    void execute() {

    If payee.getHolder().isMonitored() then

    // send record to police

    payer.withdraw(amount)

    payee.deposit(amount)

    }

    payer 1

    *

    monitored : Boolean

    getHolder() : Customer isMonitored() : Boolean

    L f D t R f t d

  • 8/13/2019 OO Design Principles & Metrics

    26/44

    Jason Gorman 2006

    www.parlezuml.com

    Law of Demeter - Refactored

    Reasoning:Objects should only collaborate with their nearest neighbours the less they depend on the

    interfaces of friends of a friend, the less reasons they might have to have to change. This

    means avoiding long navigations and deferring knowledge of interactions with objects that

    arent directly related to your nearest neighbours.

    Pseudo code:

    void execute() {

    If payee.isHolderMonitored() then

    // send record to police

    payer.withdraw(amount)

    payee.deposit(amount)

    }

    FundsTransfer

    amount : Real

    execute(amount : Real)

    Account Customerpayee

    1 1

    holder

    **

    payer 1

    *

    monitored : Boolean

    getHolder() : Customer

    isHolderMonitored() :Boolean

    isMonitored() : Boolean

    Pseudo code:

    boolean isHolderMonitored() {

    return holder.isMonitored()

    }

    L f D t M t i

  • 8/13/2019 OO Design Principles & Metrics

    27/44

    Jason Gorman 2006

    www.parlezuml.com

    Law of Demeter - Metrics

    average depth of navigation

    FundsTransfer

    amount : Real

    execute(amount : Real)

    Account Customerpayee

    1 1

    holder

    **

    Pseudo code:

    void execute() {

    If payee.getHolder().isMonitored() then

    // send record to police

    payer.withdraw(amount)

    payee.deposit(amount)

    }

    payer 1

    *

    monitored : Boolean

    getHolder() : Customer isMonitored() : Boolean

    automation possible

    R d Ab t ti

  • 8/13/2019 OO Design Principles & Metrics

    28/44

    Jason Gorman 2006

    www.parlezuml.com

    Reused Abstractions

    Reasoning:In test-driven development, abstractions are discovered by looking for similarities between

    classes or interfaces. Designers should distinguish between bone fide abstractions and

    indirection. A bone fide abstraction incorporates shared elements of two or more types into a

    single, shared abstraction to which both types conform. When we create arbitraryabstractions (e.g., interfaces for mock object tests), we create an extra maintenance burden

    with no pay off in term so removal of duplication.

    In simpler terms, abstractions should be extended or implemented by more than one class.

    CashAccount CurrentAccount SavingsAccount

    Account

    AccountImpl

    Account

    CustomerImpl

    Customer

    Abstraction Indirection

    R d Ab t ti M t i

  • 8/13/2019 OO Design Principles & Metrics

    29/44

    Jason Gorman 2006

    www.parlezuml.com

    Reused Abstractions - MetricsFor an abstract class or interface T, which is extended or implemented by N classes or

    interfaces, such that N > 1

    CashAccount CurrentAccount SavingsAccount

    Account

    AccountImpl

    Account

    CustomerImpl

    Customer

    Abstraction Indirection

    automation possible

    N = 3 N = 1 N = 1

  • 8/13/2019 OO Design Principles & Metrics

    30/44

    Jason Gorman 2006

    www.parlezuml.com

    Package Design

    Cohesion

    Release-Reuse Equivalency Common Closure

    Common Reuse

    Coupling

    Acyclic Dependencies

    Stable Dependencies

    Stable Abstractions

  • 8/13/2019 OO Design Principles & Metrics

    31/44

    Jason Gorman 2006

    www.parlezuml.com

    Release-Reuse Equivalency

    banking

    Reasoning:When developers reuse* a class, they do not want to have to recompile their

    code every time that class changes. There must be a controlled release process

    through which the class can be reused. In .NET, the unit of release is the

    assembly, so the unit of reuse is the assembly. It is for this reason that classes

    that are highly dependent and therefore will be reused together - must bepackaged in the same assembly.

    The unit of reuse is the unit of release

    FundsTransfer

    amount : Real

    execute(amount : Real)

    Account Customerpay ee

    1 1

    holder

    **

    pay er 1

    *

    monitored : Boolean

    getHolder() : CustomerisHolderMonitored() :Boolean

    isMonitored() : Boolean

  • 8/13/2019 OO Design Principles & Metrics

    32/44

    Jason Gorman 2006

    www.parlezuml.com

    Common Closure

    banking

    Reasoning:A software application will be made up of many packages, and a change in one

    package can force changes to other packages. This increases the overhead of

    the build and release cycle, so seek to minimise package dependencies by

    grouping dependent classes together.

    Classes that change together, belong together.

    FundsTransfer

    amount : Real

    execute(amount : Real)

    Account Customerpay ee

    1 1

    holder

    **

    pay er 1

    *

    monitored : Boolean

    getHolder() : CustomerisHolderMonitored() :Boolean

    isMonitored() : Boolean

  • 8/13/2019 OO Design Principles & Metrics

    33/44

    Jason Gorman 2006

    www.parlezuml.com

    Common Reuse

    banking

    Reasoning:If packages are highly cohesive then a dependency on a package is a

    dependency on every class in that package.

    Classes that arent reused together, dont belong together.

    FundsTransfer

    amount : Real

    execute(amount : Real)

    Account Customerpay ee

    1 1

    holder

    **

    pay er 1

    *

    monitored : Boolean

    getHolder() : CustomerisHolderMonitored() :Boolean

    isMonitored() : Boolean

  • 8/13/2019 OO Design Principles & Metrics

    34/44

    Jason Gorman 2006

    www.parlezuml.com

    Package Cohesion Metrics

    banking

    FundsTransfer

    amount : Real

    execute(amount : Real)

    Account Customerpay ee

    1 1

    holder

    **

    pay er 1

    *

    monitored : Boolean

    getHolder() : CustomerisHolderMonitored() :Boolean

    isMonitored() : Boolean

    Class C depends directly or indirectly on N classes in the same

    package P

    There are M classes in P

    Common reuse & common closure with respect to C is N/(M 1)

    Package cohesion for P is the average of N/(M 1) across all classes

    in P

    Except w hen M

  • 8/13/2019 OO Design Principles & Metrics

    35/44

    Jason Gorman 2006

    www.parlezuml.com

    Acyclic DependenciesReasoning:To build and release a package, we must first build and release the packages it

    depends on. If somehow the package depends indirectly on itself, then you

    create a potentially much longer build and release cycle.

    Packages must not be indirectly dependent on themselves

    A

    B

    C

    D

    To build and release any package

    except C, we have to build andrelease allpackages because A, B

    and D are indirectly dependent on

    themselves

    Class1Class2

  • 8/13/2019 OO Design Principles & Metrics

    36/44

    Jason Gorman 2006

    www.parlezuml.com

    Acyclic Dependencies - RefactoredEvery package structure must be a Directed Acyclic Graph

    A

    B

    C

    D

    Move dependent classes into same

    package

    Class1Class2

  • 8/13/2019 OO Design Principles & Metrics

    37/44

    Jason Gorman 2006

    www.parlezuml.com

    Acyclic Dependencies - MetricsNo. of cycles in package graph=> Should not be > 0

    A

    B

    C

    D

    Class1Class2

    automation possible

    Stable Dependencies

  • 8/13/2019 OO Design Principles & Metrics

    38/44

    Jason Gorman 2006

    www.parlezuml.com

    Stable Dependencies

    A

    B

    C

    Reasoning:There are tw o reasons why we might need to change code in a package.

    1. Because we want to (because the logic or design changes)

    2. Because changes in another package force us to

    It is for that reason that packages should depend on packages that are more stable. Package B has two other packages depending upon

    it. A change in package B might force us to make changes in A and C. We say that B is stable because the effort required to change code

    in B w ill be higher, and therefore were less likely to do it. Package A depends on B and C, and therefore is more l ikely to have to changebecause of changes in those packages. We say that B is instable.

    Packages must depend on more stable packages

    Stable Dependencies

  • 8/13/2019 OO Design Principles & Metrics

    39/44

    Jason Gorman 2006

    www.parlezuml.com

    Stable Dependencies

    A

    B

    C

    Reasoning:There are tw o reasons why we might need to change code in a package.

    1. Because we want to (because the logic or design changes)

    2. Because changes in another package force us to

    It is for that reason that packages should depend on packages that are more stable. Package B has two other packages depending upon

    it. A change in package B might force us to make changes in A and C. We say that B is stable because the effort required to change code

    in B w ill be higher, and therefore were less likely to do it. Package A depends on B and C, and therefore is more l ikely to have to changebecause of changes in those packages. We say that B is instable.

    Packages must depend on more stable packages

    Stable Dependencies -Metrics

  • 8/13/2019 OO Design Principles & Metrics

    40/44

    Jason Gorman 2006

    www.parlezuml.com

    Stable Dependencies -Metrics

    I = 2/(2 + 0) = 1

    AI = 0/(0 + 2) = 0

    B

    I = 1/(1+1) = 0.5

    C

    For a package P, efferent couplings Ce is the number of packages that classes in P depend upon

    For a package P, afferent couplings Ca is the number of packages that have classes that depend

    upon P

    Instability, I = Ce/(Ce + Ca)

    automation possible

    stable

    instable

    St bl Ab t ti

  • 8/13/2019 OO Design Principles & Metrics

    41/44

    Jason Gorman 2006

    www.parlezuml.com

    Stable AbstractionsReasoning:Should all software be stable? If our goal is ease of change, then a totally stable package presents a problem. But theOpen-Closed principle offers a loophole: a stable package can be easy to extend. By making stable packages abstract,

    they can easily be extended by less stable packages w hich are easier to change. This is Dependency Inversion at thepackage level.

    Packages must depend on more abstract packages.

    trading

    StockPurchaseTx SettlementAccount

    banking

    Transaction Account

    1*

    St bl Ab t ti M t i

  • 8/13/2019 OO Design Principles & Metrics

    42/44

    Jason Gorman 2006

    www.parlezuml.com

    Stable Abstractions - MetricsAbstractness A = abstract types / all types in package Package X depends on set of packages S

    Count of packages P in S where abstractness of P abstractness of X > 0 / total number of packages in S

    trading

    StockPurchaseTx SettlementAccount

    banking

    Transaction Account

    1*

    automation possible

    Ab t t I t bilit M t i

  • 8/13/2019 OO Design Principles & Metrics

    43/44

    Jason Gorman 2006

    www.parlezuml.com

    Abstractness vs. Instability - Metrics

    Reasoning:Stable packages should be open to extension, whereas instable packages

    should be easy to modify. Therefore we seek a balance between abstractness

    and instability

    Packages that are more stable should be more abstract

    A

    I

    A + I = 1

    automation possible

    zone of pain = totally stable but

    not open to extension

    zone of uselessness = totally

    abstract but not extended

    Distance from main sequence, D = |A + I 1| / Y2

    Normalised distance from main sequence, D = |A + I 1|

    R f

  • 8/13/2019 OO Design Principles & Metrics

    44/44

    Jason Gorman 2006

    www.parlezuml.com

    References

    Design Principles & Design Patterns Robert C. Martin, ObjectMentor 2000

    http://www.objectmentor.com/resources/articles/Principles_and_Patterns.PDF