In this chapter, we discuss representative and non-representative parts of a program with respect to modeling a given domain.
A primary focus of this book has been to emphasize that programming is modeling in the sense that programming is about creating a model of the relevant aspects of the application domain. This implies that one should attempt to represent descriptions of phenomena and their properties by corresponding language elements in the program.
There will, however be elements in a given program that do not relate to phenomena or concepts from the application domain. This is due to the fact that it must be possible to execute the program on a computer. To do this, part of a program will be elements that implements the parts that relate to the model of the application domain.
The part of the program that describes phenomena and concepts from the application domain is called the representative part. The part which is not representative is called non-representative.
Non-representative parts of class Account
In the following we consider class Account
in the bank domain with respect to representative and non-representative parts.
In the previous versions of Account
there is at a first glance no attributes that cannot be considered representative. All of owner
, balance
, interestRate
, deposit
, withdraw
, etc. are meaningful in the bank domain.
We originally introduced assignments like:
account_1010.balance := 523.07
and said that such an assignment may be considered a deposit on the account. And further assignments like:
account_1010.balance := account_1010.balance + 200
account_1010.balance := account_1010.balance - 300
may also be considered deposits or withdrawals.
However, we have methods deposit
and withdraw
, which are supposed to represent deposits and withdrawals of money on the account. And from a modeling point of view these conflict with assigning to balance
directly.
In addition, there is more to a deposit
and withdraw
than just updating balance
. In section , we introduced class Transactions
and an object transaction
. which keeps track of deposits and withdrawals on a given account. We would thus want to prevent access to balance
from outside the Account
-objects.
However, we do want to be able to read/print the current balance of a given account. In addition, we may want to log that someone has read the balance of an account.
We may handle this by adding a method getBalance
to the class Account
:
getBalance -> bal: var float: transact
bal := balance
theTransaction.what := “getBalance”
The above considerations also apply to the variable interestRate
. Here we do not want to be able to manipulate interestRate
directly from outside an account just as update of an interesRate
may imply more actions to be carried out. This may include informing the customer about the change.
We may thus introduce a method getInterestRate
like getBalance
and we may introduce methods setInterestRate
and getInterestRate
.
In the following we introduce language mechanism for controlling the accessibility to attributes.
Måske bruge class Set som ex?
Visibility mechanisms
Here we introduce some language mechanisms that may be used to separate the representative elements from the non-representative elements. The language elements are called access modifiers and they may specify the accessibility of attributes of an object. Access modifiers define the scope and visibility of these attributes in the code. This means that the programmer may specify to what extent a local data-item, method or class may be accessed in other parts of the code.
The most common types of access modifiers are public, private, and protected, but some languages support more as is the case for qBeta (see below). Each access modifier provides different levels of access.
Kan vi finde et andet navn for protected – siger jo ikke noget om hvad det betyder og begyndere kan have problemer med at huske forskellen mellem private og protected. OLM: i qbeta hedder den pt faktisk %publicinsub – bedre med %visibleinsub
Og vi skal også have et andet navn for domain,
%private
As a first example, we will show how to use the access modifier %private
to protect balance
and interestRate
of Account
objects:
class Account(owner: var String):
addInterest: -"-
deposit(amount: var float): -"-
withdraw(amount: var float) -> newB: var float: -"-
getBalance -> bal: var float: -"-
getInterestRate -> iRate: var float: ...
setInterestRate(iRate: var float): ...
%private
balance: var float
interestRate: var float
The access modifier %private
before the declarations of balance
and interestRate
specfies that balance and interestRate
may only be accessed within class Account
.
%protected
When using %private
in class Account
as above, no other classes or objects may acces balance
and interestRate
. However, this may be inconvenient for subclasses of Account
like SavingsAccount
, where we may add methods that manipulate these attributes.
The access modifier %protected
may be used to specify that some attributes may only be accessed within a class and its subclasses.
Så protected er det samme som private for klassen den står i. OLM: ja – er det ikke det i SIMULA?
We may thus revise class Account
as follows:
class Account:
-"-
%protected
balance: var float
interestRate: var float
class SavingsAccout: Account
-- balance and interestRate may now be accessed here
-"-
aClerk: obj
-- balance and interestRate may not be accessed
-"-
%public
For completeness, the access modifier %public
may be used to specify that some attributes are visible outside the class/object-descriptor +++ her står der descriptor, mens ovenfor står der object; descriptor er vel det rigtige. However, %public
is default in qBeta – if no access modifier is specified for some attributes they are visible outside the object-descriptor. Sometimes it may be useful to use %public
if one prefer to have e.g. the private attributes appearing before the ones that are public. This is the case for the version of class Account
below:
class Account:
%protected
balance: var float
interestRate: var float
%public
addInterest: -"-
-"-
Here balance
and interestRate
are declared in the beginning as %protected
followed by the methods of the class – these are thus explicitly declared as %public
.
%domain
Mangler så et eksempel med %domain.
2024-08-12: Men kræver at moduler er indført, så måske vi skal forklare den i kapitlet om moduler og så henvise til det?
Af de eksempler vi pt har er det kun ExpressionGrammar der er delt op i moduler på den måde at ExpressionGrammar har nested moduler expParser og expAST. Og der er ikke attributter i dem så det gir mening at de kune kan tilgås indenfor ExpressionGrammar.
Iøvrigt skal vi ha et bedre navn, da %domain jo ikke går på application domain.
Kan være noget med %module, men er i brug til inklusion af moduler, måske %in_module og %module_boundary
TopModule: module
%module_boundary
...
mod1: module
...
%in_module
foo: ...
...
mod2: module
...
%in_module
bar: ...
...
foo og bar er så synlige i TopModule og mod1 og mod2
Men lidt lange navne – har set på whole, aggregate, group, package, cluster, bundle, …
Måske %package, %package_boundary (eller blot %boundary)
Summary of access modifiers
In this section we summarize the description of access modifiers – we use the following sketchy example:
class T:
...
%public
X: var integer
m(...):
...
%private
Y: var integer
L: obj Set(integer)
...
%protected
Z: var integer
S: ref Person
...
%domain
V: var real
foo:
...
...
The class T
is specified using the access modifiers %public
, %private,
%protected
, and %domain
.
An access modifier applies to all the attributes following the modifier, up to the next access modifier.
The next example shows a usage of class T
where we have a T
-object:
R: obj T
-- The access modifiers specify if we may acces the attributes
-- R.X, R.Y, R.Z, R.V, ...
In the next example, we have a subclass TT
of T
:
class TT: T
-- Here the access modifiers above also specify if we may access
-- X, Y, Z, V, ...
Public
The access modifier %public
specifies that one or more attributes are accessible from outside the object-descriptor where it is declared.
In the above examples X
and m
may be accessed via R.x
, R.m(...)
and as X
an m(...)
in the subclass TT
of T
.
Private
The access modifier %private
specifies that one or more attributes may only be accessed within the object-descriptor where they are declared.
This means that R.Y
and R.L
is not legal and that Y
and L
may not be accessed in the subclass TT
.
Protected
The access modifier %p
rotected is like %private
except that the attributes may be accessed in subclasses of the class where they are declared.
This means that Z
and S
may not be accessed via R.Z
and R.S
but may be accessed in all subclasses of T
.
Domain
The access modifier %domain
specifies that one or more attributes can be accessed within a set of modules. This is specific to qBeta — see the section on modules. Java has a similar mechanism for packages.
Default
If no access modifier is specified, the default is %public
.
Information hiding and encapsulation
As mentioned, access modifiers may be use to separate representative parts of a program from non-representative parts. The term information hiding is often used for a similar purpose. Information hiding is a software design principle that is used to limit the parts of a component that is accessible to its clients.
In the context of this book, we use the term component for module description?, class description?, or object-descriptor.
The primary goal of information hiding is to prevent extensive modification to clients whenever the implementation details of a component are changed. This is done by hiding implementation details that are not relevant for the use of a given component.
The term encapsulation is often used in connection to information hiding. One may think of information hiding is a design principle and encapsulation as a technical term. A component like a class is said to encapsulate attributes and hiding implementation details. A component hides information by encapsulating the information into a component which presents an interface
The term interface of a component is another important term in software design. The interface of a component is the set of attributes that are accessible by clients of the component. The attributes of a given component defined as %public
thus constitutes the interface of the component. Clients of the interface of a component will access the component purely through its interface. This way, if the implementation changes, the clients do not have to change.
The term Application Programming Interface (API) is another common term. It refers to the interface of a component, but is most often used for software modules and/programs used by other modules or programs, but technically it is an interface.
In many schools of software design, it is a common design principle that the interface of a component should be restricted to a set of methods. Data-items are primarily considered implementation details and access to data-items should therefore be limited. In object-oriented design as advocated in this book, an interface may also include local classes of a component and/or part objects.
Information hiding, encapsulation and interface are technical terms of software design. They go hand inland with programming as modeling. One way of practicing information hiding s to make sure that only representative parts of a module are visible to clients and thus provides the interface. Non-representative parts correspond to implementation. Modules, classes and object-descriptors are language mechanisms for supporting encapsulation supplemented by access modifiers.
Skal vi sige mere om hvordan man kan praktisere information hiding?
Shall we mention abstraction barriers, layers, etc.
Tekset nedenfor er klip fra nettet der blot skal bruges om input
Information hiding serves as a criterion that can be used to decompose a system into modules. The principle is also useful for reducing coupling within a system.
A common use of information hiding is to hide the physical storage layout for data so that if it is changed, the change is restricted to a small subset of the total program. For example, if a three-dimensional point (x, y, z) is represented in a program with three floating-point scalar variables and later, the representation is changed to a single array variable of size three, a module designed with information hiding in mind would protect the remainder of the program from such a change.
This link has some guidelines for information hiding: https://embeddedartistry.com/fieldmanual-terms/information-hiding/