codex/past-exam-of-the-year-1-of-the-computer-science-course-of-the-university-of-oxford/2016/imperative-resit-observer-uml.py

past-exam-of-the-year-1-of-the-computer-science-course-of-the-university-of-oxford/2016/imperative-resit-observer-uml.py
"""Service observer UML. Python 3.14; matplotlib 3.10.7; writes PNG to CWD."""
from pathlib import Path
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, FancyArrowPatch


def main():
    fig,ax=plt.subplots(figsize=(13.5,7.4),facecolor='white')
    ax.set(xlim=(0,18.3),ylim=(0,9.6))
    ax.axis('off')
    def box(x,y,w,h,title,body,tint='#f2f6fa'):
        ax.add_patch(Rectangle((x-w/2,y-h/2),w,h,facecolor=tint,
                     edgecolor='#25364a',lw=1.4,zorder=3))
        split=y+h/2-.55
        ax.plot([x-w/2,x+w/2],[split,split],color='#25364a',lw=1,zorder=4)
        ax.text(x,y+h/2-.27,title,ha='center',va='center',fontsize=11,
                weight='bold',zorder=5)
        ax.text(x-w/2+.12,split-.16,body,ha='left',va='top',fontsize=10.5,
                linespacing=1.5,zorder=5)
    def edge(start,end,dashed=False):
        ax.add_patch(FancyArrowPatch(start,end,arrowstyle='-|>',mutation_scale=20,
                     edgecolor='#25364a',facecolor='white',linewidth=1.3,
                     linestyle='--' if dashed else '-',zorder=1))
    box(3.0,7.15,5.1,3.1,'«trait» Service',
        '- _value: Double\n- companies: List[Company]\n+ value / value_=\n+ addCompany(c), sendMessage()\n+ updateValue(newValue)')
    box(11.5,7.55,4.0,1.6,'«interface» Company','+ meth(): Unit')
    ax.annotate('',xy=(9.5,7.55),xytext=(5.55,7.55),
                arrowprops=dict(arrowstyle='->',color='#25364a',lw=1.3))
    ax.text(7.5,7.8,'companies  0..*',ha='center',fontsize=10.5)
    ax.text(7.5,7.1,'notify: meth()',ha='center',fontsize=10.5)
    box(3.0,2.65,5.1,2.0,'SomeService',
        '+ updateValue(newValue):\n  set value, then notify')
    edge((3,3.65),(3,5.60))
    for x,name,factor in [(8.0,'PrivateCompany','1.1'),
                           (12.0,'PublicCompany','0.9'),
                           (16.0,'NonProfit','1.0')]:
        box(x,2.65,3.7,2.3,name,
            '- service: SomeService\n- v: Double\n+ meth(): refresh v',
            '#fff6df' if name=='NonProfit' else '#f2f6fa')
        edge((x,3.8),(11.5,6.75),True)
        ax.text(x,1.0,'callback factor '+factor,ha='center',fontsize=10)
    ax.text(.5,9.1,'Service values: subject registers and notifies company observers',
            fontsize=14,weight='bold')
    ax.text(.5,.35,'Each concrete company retains one SomeService and registers itself with it.',
            fontsize=10.5,color='#354354')
    fig.tight_layout(pad=.6)
    fig.savefig(Path.cwd()/'imperative-resit-observer-uml.png',dpi=115,
                facecolor='white',transparent=False)
    plt.close(fig)


if __name__ == '__main__':
    main()