Generic Collection Class: Motivation (2) Use of Generic Parameters Iterator and Singleton Patterns

Similar documents
Use of Generic Parameters Iterator and Singleton Patterns

Singleton Pattern: Motivation. Design Patterns: Singleton and Iterator. What are design patterns? Shared Data through Inheritance

Commands, and Queries, and Features. Syntax of Eiffel: a Brief Overview. Escape Sequences. Naming Conventions

Syntax of Eiffel: a Brief Overview

Abstract Data Types (ADTs), Classes, and Objects

Test-Driven Development (TDD)

Abstractions via Mathematical Models

Motivating Problem: LIFO Stack (1) Abstractions via Mathematical Models. Motivating Problem: LIFO Stack (2.1) Motivating Problem: Complete Contracts

Motivating Problem: LIFO Stack (1) Abstractions via Mathematical Models. Motivating Problem: LIFO Stack (2.1) Motivating Problem: Complete Contracts

Assertions. Assertions - Example

References: internet notes; Bertrand Meyer, Object-Oriented Software Construction; 10/14/2004 1

What This Course Is About Design-by-Contract (DbC)

Generics in Java. EECS2030: Advanced Object Oriented Programming Fall 2017 CHEN-WEI WANG

Motivating Example: Observations (1) Generics in Java. Motivating Example: A Book of Objects. Motivating Example: Observations (2)

Introduction to Eiffel

Introduction to Programming Using Java (98-388)

Design-by-Contract (Dbc) Test-Driven Development (TDD)

Singleton Pattern Creational. » Ensure a class has only one instance» Provide a global point of access

Client, Supplier, Contract in OOP (1) Design-by-Contract (Dbc) Test-Driven Development (TDD) Terminology: Contract, Client, Supplier

Catching Defects: Design or Implementation Phase? Design-by-Contract (Dbc) Test-Driven Development (TDD) Motivation of this Course

Tutorial on ETF: the Eiffel Testing Framework Building a Bank System

Universe Type System for Eiffel. Annetta Schaad

The State Design Pattern

1. Quality issues (5 points)

Singleton Pattern Creational

Encapsulation in Java

The Visitor Design Pattern

Software Architecture 4. July 2005

Object-Oriented Software Construction

Semantic Analysis. CSE 307 Principles of Programming Languages Stony Brook University

Automatic Verification of Computer Programs

Why Design by Contract! CS 619 Introduction to OO Design and Development. Design by Contract. Fall 2012

Mock exam 1. ETH Zurich. Date: 9./10. November 2009

EINDHOVEN UNIVERSITY OF TECHNOLOGY

Lethbridge/Laganière 2005 Chapter 9: Architecting and designing software 6


Einführung in die Programmierung Introduction to Programming

Lecture Chapter 2 Software Development

Einführung in die Programmierung Introduction to Programming

Formal Methods for Java

CMSC 433 Section 0101 Fall 2012 Midterm Exam #1

JAVA: A Primer. By: Amrita Rajagopal

Course Text. Course Description. Course Objectives. StraighterLine Introduction to Programming in C++

CS-140 Fall 2017 Test 1 Version Practice Practie for Sept. 27, Name:

Data Structures and Abstract Data Types

Index. Index. More information. block statements 66 y 107 Boolean 107 break 55, 68 built-in types 107

Solution 9: Data structures

In-Class Exercises. ETH Zurich. November

Chapter 1: Programming Principles

The Eiffel language. Slides partly based on :

CSE 331. Programming by contract: pre/post conditions; Javadoc

Assignment 2 - Specifications and Modeling

Control flow in Eiffel

Eiffel Loops & Iteration

Object-oriented basics. Object Class vs object Inheritance Overloading Interface

Lecture 7: Data Abstractions

UNIT 3 ARRAYS, RECURSION, AND COMPLEXITY CHAPTER 11 CLASSES CONTINUED

Lecture 13: Introduction to inheritance and genericity

CSI33 Data Structures

TIME: 3 HOURS MARKS: a. Develop a java program to sort an array of N numbers in ascending order. (40)

SQL STORED ROUTINES. CS121: Relational Databases Fall 2017 Lecture 9

Lecture 14: More Inheritance & Genericity

Spring 2003 Instructor: Dr. Shahadat Hossain. Administrative Matters Course Information Introduction to Programming Techniques

PROGRAMMING IN C AND C++:

Self-review Questions

SRM ARTS AND SCIENCE COLLEGE SRM NAGAR, KATTANKULATHUR

CO Java SE 8: Fundamentals

CS246 Software Abstraction and Specification Final Examination

BON Business Object Notation Based on slides by Prof. Paige

VALLIAMMAI ENGNIEERING COLLEGE SRM Nagar, Kattankulathur DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING QUESTION BANK

Java: advanced object-oriented features

The Dependent Delegate Dilemma

SFPL Simple Floor Plan Language 09/25/2005

Programming with Contracts. Juan Pablo Galeotti, Alessandra Gorla Saarland University, Germany

XII- COMPUTER SCIENCE VOL-II MODEL TEST I

III lecture: Contracts and Abstract Data Types. An obligation from last lecture... An obligation from last lecture... (2) January/February 2013

Introduction C H A P T E R1. Exercises

Adding Contracts to C#

3. Design by Contract

Introduction to Computers and C++ Programming p. 1 Computer Systems p. 2 Hardware p. 2 Software p. 7 High-Level Languages p. 8 Compilers p.

Software Architecture. Abstract Data Types

Inheritance Readings: OOSCS2 Chapters 14 16

Defensive Programming

Motivating Problem (2) Design for tree structures with whole-part hierarchies. The Composite Design Pattern

Chapter 6 Introduction to Defining Classes

Testing, Debugging, and Verification

Constants, once routines, and helper functions

Object Oriented Programming with Java

15-418, Spring 2008 OpenMP: A Short Introduction

Introduction to Visual Basic and Visual C++ Introduction to Java. JDK Editions. Overview. Lesson 13. Overview

Lecture 10 Design by Contract

Overview The Java Modeling Language (Part 1) Related Work

A Eiffel: The Essentials

Data Structures. BSc in Computer Science University of New York, Tirana. Assoc. Prof. Marenglen Biba 1-1

Assertions, pre/postconditions

Object-Oriented Concepts and Design Principles

Object Oriented Program Correctness with OOSimL

Object Oriented Programming 2013/14. Final Exam June 20, 2014

Runtime Checking for Program Verification Systems

Assertions & Verification & Example Loop Invariants Example Exam Questions

Transcription:

Generic Collection Class: Motivation (2) Use of Generic Parameters Iterator and Singleton Patterns EECS3311 A: Software Design Fall 2018 CHEN-WEI WANG ACCOUNT _STACK {NONE -- Implementation imp: ARRAY[ ACCOUNT ] ; i: INTEGER -- Queries count: INTEGER Result := i -- Number of items on stack. top: ACCOUNT Result := imp [i] -- Return top of stack. -- Commands push (v: ACCOUNT ) imp[i] := v; i := i + 1 -- Add v to top of stack. pop i := i - 1 -- Remove top of stack. Does how we implement integer stack operations (e.g., top, push, pop) deps on s specific to element type ACCOUNT (e.g., deposit, withdraw)? [ NO! ] A collection (e.g., table, tree, graph) is meant for the storage and retrieval of elements, not how those elements are manipulated. 3 of 42 Generic Collection Class: Motivation (1) STRING _STACK {NONE -- Implementation imp: ARRAY[ STRING ] ; i: INTEGER -- Queries count: INTEGER Result := i -- Number of items on stack. top: STRING Result := imp [i] -- Return top of stack. -- Commands push (v: STRING ) imp[i] := v; i := i + 1 -- Add v to top of stack. pop i := i - 1 -- Remove top of stack. Does how we implement integer stack operations (e.g., top, push, pop) deps on s specific to element type STRING (e.g., at, app)? [ NO! ] How would you implement another ACCOUNT STACK? 2 of 42 Generic Collection Class: Supplier Your design smells if you have to create an almost identical new (hence code duplicates ) for every stack element type you need (e.g., INTEGER, CHARACTER, PERSON, etc.). Instead, as supplier, use G to parameterize element type: STACK [G] {NONE -- Implementation imp: ARRAY[ G ] ; i: INTEGER -- Queries count: INTEGER Result := i -- Number of items on stack. top: G Result := imp [i] -- Return top of stack. -- Commands push (v: G ) imp[i] := v; i := i + 1 -- Add v to top of stack. pop i := i - 1 -- Remove top of stack. 4 of 42

Generic Collection Class: Client (1.1) As client, declaring ss: STACK[ STRING ] instantiates every occurrence of G as STRING. STACK [G STRING] {NONE -- Implementation imp: ARRAY[ G STRING ] ; i: INTEGER -- Queries count: INTEGER Result := i -- Number of items on stack. top: G STRING Result := imp [i] -- Return top of stack. -- Commands push (v: G STRING ) imp[i] := v; i := i + 1 -- Add v to top of stack. pop i := i - 1 -- Remove top of stack. 5 of 42 Generic Collection Class: Client (2) As client, instantiate the type of G to be the one needed. 1 test_stacks: BOOLEAN 2 local 3 ss: STACK[STRING] ; sa: STACK[ACCOUNT] 4 s: STRING ; a: ACCOUNT 5 6 ss.push("a") 7 ss.push(create {ACCOUNT.make ("Mark", 200)) 8 s := ss.top 9 a := ss.top 10 sa.push(create {ACCOUNT.make ("Alan", 100)) 11 sa.push("b") 12 a := sa.top 13 s := sa.top 14 L3 commits that ss stores STRING objects only. L8 and L10 valid; L9 and L11 invalid. L4 commits that sa stores ACCOUNT objects only. L12 and L14 valid; L13 and L15 invalid. 7 of 42 Generic Collection Class: Client (1.2) As client, declaring ss: STACK[ ACCOUNT ] instantiates every occurrence of G as ACCOUNT. STACK [G ACCOUNT] {NONE -- Implementation imp: ARRAY[ G ACCOUNT ] ; i: INTEGER -- Queries count: INTEGER Result := i -- Number of items on stack. top: G ACCOUNT Result := imp [i] -- Return top of stack. -- Commands push (v: G ACCOUNT ) imp[i] := v; i := i + 1 -- Add v to top of stack. pop i := i - 1 -- Remove top of stack. What are design patterns? Solutions to recurring problems that arise when software is being developed within a particular context. Heuristics for structuring your code so that it can be systematically maintained and exted. Caveat : A pattern is only suitable for a particular problem. Therefore, always understand problems before solutions! 6 of 42 8 of 42

Motivation (1) Client: Architecture Supplier: CART orders: ARRAY[ORDER] ORDER price: INTEGER quantity: INTEGER Problems? SHOP cart: CART checkout: INTEGER from i := cart.orders.lower until i > cart.orders.upper Result := Result + cart.orders[i].price * cart.orders[i].quantity i := i + 1 CLIENT CLIENT_APPLICATION+ container: ITERABLE+ -- Fresh cursor of the container. increase_balance(v: INTEGER; name: STRING) -- Increase the balance for account with owner name.? across container as cur all cur.item.balance v! across old container.deep_twin as cur all (cur.item.owner ~ name implies cur.item.balance = old cur.item.balance + v) and (cur.item.owner ~ name implies cur.item.balance = old cur.item.balance) some_account_negative: BOOLEAN -- Is there some account negative?! Result = across container as cur some cur.item.balance < v container+ SUPPLIER ITERABLE * ITERATION_CURSOR[G] * new_cursor*: ITERATION_CURSOR[G] after*: BOOLEAN -- Fresh cursor associated with current structure. -- Are there no more items to iterate over?! Result Void new_cursor* item*: G -- Item at current cursor position.? valid_position: not after forth* -- Move to next position.? valid_position: not after INDEXABLE_ITERATION_CURSOR[G] + ARRAY[G] + after+: BOOLEAN -- Are there no more items to iterate over? new_cursor+ item+: G -- Item at current cursor position. forth+ LINKED_LIST[G] + ARRAYED_LIST[G] + -- Move to next position. start+ -- Move to first position. ITERABLE_COLLECTION 9 of 42 11 of 42 Motivation (2) Supplier: CART orders: LINKED LIST[ORDER] ORDER price: INTEGER quantity: INTEGER Client s code must be modified to adapt to the supplier s change on implementation. 10 of 42 Client: SHOP cart: CART checkout: INTEGER from cart.orders.start until cart.orders.after Result := Result + cart.orders.item.price * cart.orders.item.quantity Supplier s Side Information Hiding Principle : Hide design decisions that are likely to change (i.e., stable API). Change of secrets es not affect clients using the existing API. e.g., changing from ARRAY to LINKED LIST in the CART Steps: 1. Let the supplier inherit from the deferred ITERABLE[G]. 2. This forces the supplier to implement the inherited : new cursor: ITERATION CURSOR [G], where the type parameter G may be instantiated (e.g., ITERATION CURSOR[ORDER]). 2.1 If the internal, library data structure is already iterable e.g., imp: ARRAY[ORDER], then simply return imp.new cursor. 2.2 Otherwise, say imp: MY TREE[ORDER], then create a new MY TREE ITERATION CURSOR that inherits from ITERATION CURSOR[ORDER], then implement the 3 inherited s after, item, and forth accordingly. 12 of 42

Supplier s Implementation (1) CART inherit ITERABLE[ORDER] {NONE -- Information Hiding orders: ARRAY[ORDER] -- Iteration new_cursor: ITERATION_CURSOR[ORDER] Result := orders.new_cursor When the secrete implementation is already iterable, reuse it! 13 of 42 Supplier s Imp. (2.2) MY_ITERATION_CURSOR[G] inherit ITERATION_CURSOR[ TUPLE[STRING, G] ] -- Constructor make (ns: ARRAY[STRING]; rs: ARRAY[G]) {NONE -- Information Hiding cursor_position: INTEGER names: ARRAY[STRING] records: ARRAY[G] -- Cursor Operations item: TUPLE[STRING, G] after: Boolean forth You need to implement the three inherited s: item, after, and forth. 15 of 42 Supplier s Imp. (2.1) Supplier s Imp. (2.3) GENERIC_BOOK[G] inherit ITERABLE[ TUPLE[STRING, G] ] {NONE -- Information Hiding names: ARRAY[STRING] records: ARRAY[G] -- Iteration new_cursor: ITERATION_CURSOR[ TUPLE[STRING, G] ] local cursor: MY ITERATION CURSOR[G] create cursor.make (names, records) Result := cursor Visualizing iterator pattern at runtime: ArrayedMap inherit ITERABLE[TUPLE[STRING, G]] names records new_cursor ITERATION_CURSOR[TUPLE[STRING, G]] values_1 values_2 cursor_position item after, forth 1 1 2 3 names.upper 1 2 3 records.upper No Eiffel library support for iterable arrays Implement it yourself! 14 of 42 16 of 42

Exercises Client s Side 1. Draw the BON diagram showing how the iterator pattern is applied to the CART (supplier) and SHOP (client) es. 2. Draw the BON diagram showing how the iterator pattern is applied to the supplier es: GENERIC BOOK (a descant of ITERABLE) and MY ITERATION CURSOR (a descant of ITERATION CURSOR). Information hiding : the clients not at all dep on how the supplier implements the collection of data; they are only interested in iterating through the collection in a linear manner. Steps: 1. Obey the code to interface, not to implementation principle. 2. Let the client declare an attribute of interface type ITERABLE[G] (rather than implementation type ARRAY, LINKED LIST, or MY TREE). e.g., cart: CART, where CART inherits ITERATBLE[ORDER] 3. Eiffel supports, in both implementation and contracts, the across syntax for iterating through anything that s iterable. 17 of 42 19 of 42 Resources Tutorial Videos on Generic Parameters and the Iterator Pattern Tutorial Videos on Information Hiding and the Iterator Pattern 18 of 42 Clients using across for Contracts (1) CHECKER -- Attributes collection: ITERABLE [INTEGER] -- Queries is all positive: BOOLEAN -- Are all items in collection positive? ensure across collection as cursor all cursor.item > 0 Using all corresponds to a universal quantification (i.e., ). Using some corresponds to an existential quantification (i.e., ). 20 of 42

Clients using across for Contracts (2) BANK accounts: LIST [ACCOUNT] binary_search (acc_id: INTEGER): ACCOUNT -- Search on accounts sorted in non-descing order. require across 1.. (accounts.count - 1) as cursor all accounts [cursor.item].id <= accounts [cursor.item + 1].id ensure Result.id = acc_id This precondition corresponds to: i INTEGER 1 i < accounts.count accounts[i].id accounts[i + 1].id 21 of 42 Clients using Iterable in Imp. (1) BANK accounts: ITERABLE [ACCOUNT] max_balance: ACCOUNT -- Account with the maximum balance value. require?? local cursor: ITERATION_CURSOR[ACCOUNT]; max: ACCOUNT from max := accounts [1]; cursor := accounts. new cursor until cursor. after if cursor. item.balance > max.balance then max := cursor. item cursor. forth ensure?? 23 of 42 Clients using across for Contracts (3) BANK accounts: LIST [ACCOUNT] contains_duplicate: BOOLEAN -- Does the account list contain duplicate? ensure i, j INTEGER 1 i accounts.count 1 j accounts.count accounts[i] accounts[j] i = j Exercise: Convert this mathematical predicate for postcondition into Eiffel. Hint: Each across construct can only introduce one dummy variable, but you may nest as many across constructs as necessary. 22 of 42 Clients using Iterable in Imp. (2) 1 SHOP 2 cart: CART 3 checkout: INTEGER 4 -- Total price calculated based on orders in the cart. 5 require?? 6 local 7 order: ORDER 8 9 across 10 cart as cursor 11 loop 12 order := cursor. item 13 Result := Result + order.price * order.quantity 14 15 ensure?? 16 Class CART should inherit from ITERABLE[ORDER]. L10 implicitly declares cursor: ITERATION CURSOR[ORDER] and es cursor := cart.new cursor 24 of 42

Clients using Iterable in Imp. (3) BANK accounts: ITERABLE [ACCOUNT] max_balance: ACCOUNT -- Account with the maximum balance value. require?? local max: ACCOUNT max := accounts [1] across accounts as cursor loop if cursor.item.balance > max.balance then max := cursor. item ensure?? 25 of 42 Shared Data via Inheritance Client: DEPOSIT inherit SHARED DATA -- maximum_balance relevant WITHDRAW inherit SHARED DATA -- minimum_balance relevant INT_TRANSFER inherit SHARED DATA -- exchange_rate relevant ACCOUNT inherit SHARED DATA -- interest_rate relevant deposits: DEPOSIT_LIST withdraws: WITHDRAW_LIST 27 of 42 Supplier: SHARED DATA interest_rate: REAL exchange_rate: REAL minimum_balance: INTEGER maximum_balance: INTEGER Problems? Singleton Pattern: Motivation Sharing Data via Inheritance: Architecture Consider two problems: 1. Bank accounts share a set of data. e.g., interest and exchange rates, minimum and maximum balance, etc. 2. Processes are regulated to access some shared, limited resources. e.g., printers 26 of 42 Irreverent s are inherited. Descants cohesion is broken. Same set of data is duplicated as instances are created. Updates on these data may result in inconsistency. 28 of 42

Sharing Data via Inheritance: Limitation Each descant instance at runtime owns a separate copy of the shared data. This makes inheritance not an appropriate solution for both problems: What if the interest rate changes? Apply the change to all instantiated account objects? An update to the global lock must be observable by all regulated processes. Solution: Separate notions of data and its shared access in two separate es. Encapsulate the shared access itself in a separate. Introducing the Once Routine in Eiffel (1.2) 1 test_query: BOOLEAN 2 local 3 a: A 4 arr1, arr2: ARRAY[STRING] 5 6 create a.make 7 8 arr1 := a.new_array ("Alan") 9 Result := arr1.count = 1 and arr1[1] "Alan" 10 check Result 11 12 arr2 := a.new_array ("Mark") 13 Result := arr2.count = 1 and arr2[1] "Mark" 14 check Result 15 16 Result := not (arr1 = arr2) 17 check Result 18 29 of 42 31 of 42 Introducing the Once Routine in Eiffel (1.1) 1 A 2 create make 3 -- Constructor 4 make 5 -- Query 6 new_once_array (s: STRING): ARRAY[STRING] 7 -- A once query that returns an array. 8 once 9 create {ARRAY[STRING] Result.make_empty 10 Result.force (s, Result.count + 1) 11 12 new_array (s: STRING): ARRAY[STRING] 13 -- An ordinary query that returns an array. 14 15 create {ARRAY[STRING] Result.make_empty 16 Result.force (s, Result.count + 1) 17 18 L9 & L10 executed only once for initialization. L15 & L16 executed whenever the is called. 30 of 42 Introducing the Once Routine in Eiffel (1.3) 1 test_once_query: BOOLEAN 2 local 3 a: A 4 arr1, arr2: ARRAY[STRING] 5 6 create a.make 7 8 arr1 := a.new_once_array ("Alan") 9 Result := arr1.count = 1 and arr1[1] "Alan" 10 check Result 11 12 arr2 := a.new_once_array ("Mark") 13 Result := arr2.count = 1 and arr2[1] "Alan" 14 check Result 15 16 Result := arr1 = arr2 17 check Result 18 32 of 42

Introducing the Once Routine in Eiffel (2) r (): T once -- Some computations on Result The ordinary is replaced by once. The first time the once routine r is called by some client, it executes the body of computations and returns the computed result. From then on, the computed result is cached. In every subsequent call to r, possibly by different clients, the body of r is not executed at all; instead, it just returns the cached result, which was computed in the very first call. How es this help us? Cache the reference to the same shared object! 33 of 42 Singleton Pattern in Eiffel (1) Supplier: DATA create {DATA ACCESS make {DATA ACCESS make v := 10 -- Data Attributes v: INTEGER change_v (nv: INTEGER) v := nv expanded DATA ACCESS data: DATA -- The one and only access once create Result.make invariant data = data 35 of 42 Client: test: BOOLEAN local access: DATA ACCESS d1, d2: DATA d1 := access.data d2 := access.data Result := d1 = d2 and d1.v = 10 and d2.v = 10 check Result d1.change_v (15) Result := d1 = d2 and d1.v = 15 and d2.v = 15 Writing create d1.make in test es not compile. Why? Approximating Once Routine in Java We may encode Eiffel once routines in Java: BankData { BankData() { uble interestrate; void setir(uble r); BankDataAccess { static boolean initonce; static BankData data; static BankData getdata() { if(!initonce) { data = new BankData(); initonce = true; return data; 34 of 42 Account { BankData data; Account() { data = BankDataAccess.getData(); Problem? Multiple BankData objects may be created in Account, breaking the singleton! Account() { data = new BankData(); Singleton Pattern in Eiffel (2) Supplier: BANK DATA create {BANK DATA ACCESS make {BANK DATA ACCESS make -- Data Attributes interest_rate: REAL set_interest_rate (r: REAL) expanded BANK DATA ACCESS data: BANK DATA -- The one and only access once create Result.make invariant data = data 36 of 42 Client: ACCOUNT data: BANK DATA make () -- Init. access to bank data. local data_access: BANK DATA ACCESS data := data_access.data Writing create data.make in client s make es not compile. Why?

Testing Singleton Pattern in Eiffel test_bank_shared_data: BOOLEAN -- Test that a single data object is manipulated local acc1, acc2: ACCOUNT comment("t1: test that a single data object is shared") create acc1.make ("Bill") create acc2.make ("Steve") Result := acc1.data = acc2.data check Result Result := acc1.data acc2.data check Result acc1.data.set_interest_rate (3.11) Result := acc1.data.interest_rate = acc2.data.interest_rate and acc1.data.interest_rate = 3.11 check Result acc2.data.set_interest_rate (2.98) Result := acc1.data.interest_rate = acc2.data.interest_rate and acc1.data.interest_rate = 2.98 37 of 42 Index (1) Generic Collection Class: Motivation (1) Generic Collection Class: Motivation (2) Generic Collection Class: Supplier Generic Collection Class: Client (1.1) Generic Collection Class: Client (1.2) Generic Collection Class: Client (2) What are design patterns? Motivation (1) Motivation (2) Architecture Supplier s Side Supplier s Implementation (1) Supplier s Imp. (2.1) Supplier s Imp. (2.2) 39 of 42 Singleton Pattern: Architecture CLIENT_1 APPLICATION_1 + CLIENT_2 APPLICATION_2 + CLIENT_3 APPLICATION_3 + DATA_ACCESS + data: DATA -- A shared data object. once create Result.make Invariant shared_instance: data = data SUPPLIER_OF_SHARED_DATA data + DATA + v: VALUE -- An example query. c -- An example command. DATA_ACCESS make - - Initialize a data object. Important Exercises: Instantiate this architecture to both problems of shared bank data and shared lock. Draw them in draw.io. 38 of 42 Index (2) Supplier s Imp. (2.3) Exercises Resources Client s Side Clients using across for Contracts (1) Clients using across for Contracts (2) Clients using across for Contracts (3) Clients using Iterable in Imp. (1) Clients using Iterable in Imp. (2) 40 of 42

Index (3) Clients using Iterable in Imp. (3) Singleton Pattern: Motivation Shared Data via Inheritance Sharing Data via Inheritance: Architecture Sharing Data via Inheritance: Limitation Introducing the Once Routine in Eiffel (1.1) Introducing the Once Routine in Eiffel (1.2) Introducing the Once Routine in Eiffel (1.3) Introducing the Once Routine in Eiffel (2) Approximating Once Routines in Java Singleton Pattern in Eiffel (1) Singleton Pattern in Eiffel (2) Testing Singleton Pattern in Eiffel 41 of 42 Index (4) Singleton Pattern: Architecture 42 of 42