Implementing View Types in Python

Truly hiding implementation details

interface Ledger {
fun getValue(i: Int): Int?
}
class LedgerImpl: Ledger {
val container = HashMap<Int, Int>()
override fun getValue(i: Int) = container.get(i)
fun process() {
// processing
}
}
fun getLedger(): Ledger {
val c = LedgerImpl()
c.process()
return c as Ledger
}

Can we achieve the same in Python?

Yes, we can mimic the above code structure in Python as follows.

from abc import ABC
from collections import defaultdict
class Ledger(ABC):
def get_value(self, i: int) -> int:
pass
class _LedgerImpl(Ledger):
def __init__(self):
self._container = defaultdict(int)
def get_value(self, i: int) -> int:
return self._container[i]
def process(self) -> None:
...
def facade() -> Ledger:
l = _LedgerImpl()
l.process()
return l

Can we do better?

(Accidentally) Yes, we can do better. We can use namedtuple support in Python to realize the view type.

from abc import ABC
from collections import defaultdict
from typing import Callable, NamedTuple
class Ledger(NamedTuple):
get_value: Callable[[int], int]
class _LedgerImpl():
def __init__(self):
self._container = defaultdict(int)
def process(self) -> None:
...
def get_view(self) -> Ledger:
return Ledger(lambda x: self._container[x])
def facade() -> Ledger:
l = _LedgerImpl()
l.process()
return l.get_view()

When should we use this pattern?

This pattern is ideal to use when implementation details need to be truly hidden.

Note

I stumbled on this pattern during my coding sessions. Since I found it to be interesting and useful, I blogged about it. That said, as with all patterns, use them only when they are required.

Programming, experimenting, writing | Past: SWE, Researcher, Professor | Present: SWE

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store