@startuml
'figure 6: The Abstract Factory Pattern'
skinparam monochrome true
skinparam handwritten false
skinparam shadowing false
skinparam classAttributeIconSize 0
hide class circle
hide abstract circle

class Client {
  + some_attr: A
  + another_attr: B
}

abstract class Factory {
    + make_A() : A
    + make_B() : B
}

abstract class A {}

abstract class B {}

Client -- Factory

Factory -> A : "makes"
Factory -> B : "makes"


package "Implementation 1" {

    class Factory_1 {
      + make_A() : A
      + make_B() : B
    }
    Factory <|-- Factory_1

    class A1 {}
    class B1 {}

    A <|-- A1
    B <|-- B1

    Factory_1::make_A --> A1
    Factory_1::make_B --> B1

}


package "Implementation 2" {

    class Factory_2 {
      + make_A() : A
      + make_B() : B
    }
    Factory <|-- Factory_2

    class A2 {}
    class B2 {}

    A <|-- A2
    B <|-- B2

    Factory_2::make_A --> A2
    Factory_2::make_B --> B2
}

@enduml

@startuml abstract_factory-classes.png
'figure 7: The Abstract Factory Pattern'
skinparam monochrome true
skinparam handwritten false
skinparam shadowing false
skinparam classAttributeIconSize 0
hide class circle
hide abstract circle

class Game {
  + deck: List[Card]
  + hand: Hand
  + deal() : Hand
  + score(hand: Hand) -> List[Trick]
}

abstract class CardGameFactory {
    + make_card(rank, suit) : Card
    + make_hand(cards) : Hand
}

abstract class Card {
    rank: int
    suit: Suit
}

abstract class Hand {
    cards: List[Card]
}

Game -- CardGameFactory

CardGameFactory -> Card : "makes"
CardGameFactory -> Hand : "makes"

Hand *-- Card

package "Cribbage" {

    class CribbageFactory {
        + make_card(rank, suit) : Card
        + make_hand(cards) : Hand
    }
    CardGameFactory <|-- CribbageFactory

    class CribbageCard {
        + points : int
    }
    class CribbageFace {}
    class CribbageAce {}
    class CribbageHand {
        + upcard(card: Card)
    }

    Card <|-- CribbageCard
    CribbageCard <|-- CribbageFace
    CribbageCard <|-- CribbageAce
    Hand <|-- CribbageHand

    CribbageFactory::make_card --> CribbageCard
    CribbageFactory::make_hand -> CribbageHand

    CribbageHand *- "4" CribbageCard
}


package "Poker" {

    class PokerFactory {
        + make_card(rank, suit) : Card
        + make_hand(cards) : Hand
    }
    CardGameFactory <|-- PokerFactory

    class PokerCard {}
    class PokerHand {}

    Card <|-- PokerCard
    Hand <|-- PokerHand

    PokerFactory::make_card --> PokerCard
    PokerFactory::make_hand -> PokerHand

    PokerHand *- "5" PokerCard
}

@enduml

@startuml factory-modules.png
'figure 8: The Abstract Factory Pattern'
skinparam monochrome true
skinparam handwritten false
skinparam shadowing false
skinparam classAttributeIconSize 0
hide class circle
hide abstract circle

class Game {
  + deck: List[Card]
  + hand: Hand
  + deal() : Hand
  + score(hand: Hand) -> List[Trick]
}

package Base {

    abstract class Card {
        rank: int
        suit: Suit
    }

    abstract class Hand {
        cards: List[Card]
    }

    Hand *-- Card
}

package "Cribbage" {

    class "CardGameFactory" as ccgf {
        + make_card(rank, suit) : Card
        + make_hand(cards) : Hand
    }

    class CribbageCard {
        + points : int
    }
    class CribbageFace {}
    class CribbageAce {}
    class CribbageHand {
        + upcard(card: Card)
    }

    Card <|-- CribbageCard
    CribbageCard <|-- CribbageFace
    CribbageCard <|-- CribbageAce
    Hand <|-- CribbageHand

    ccgf::make_card --> CribbageCard
    ccgf::make_hand --> CribbageHand

    CribbageHand *-- "4" CribbageCard
}

package "Poker" {

    class "CardGameFactory" as pcgf {
        + make_card(rank, suit) : Card
        + make_hand(cards) : Hand
    }

    class PokerCard {}
    class PokerHand {}

    Card <|-- PokerCard
    Hand <|-- PokerHand

    pcgf::make_card --> PokerCard
    pcgf::make_hand --> PokerHand

    PokerHand *-- "5" PokerCard
}

Game -- pcgf
Game -- ccgf
@enduml
