Difference between revisions of "Support pattern"

From wiki.visual-prolog.com

(No difference)

Revision as of 11:59, 13 February 2015

The purpose of the support pattern is to implement a number of target classes all supporting a common interface target, using a targetSupport class to implement common functionality. The pattern is a more explicit version of some common less structured inheritance patterns.

Even though the purpose of the pattern it so create many target classes, the pattern is described for one of these target classes. In that context there are two actors:

The targets are the class we want to implement.
The targetSupport is a class that implement those parts of the target that is to be reused/shared for other target's.

There are three contracts in the pattern:

  • The target interface, which defines the target's public interface.
  • The targetSupport interface, which defines the target's view of the targetSupport.
  • The targetSite interface, which defines the targetSupport's view of the target.

PFC has many of uses the support pattern.

The contents of the target interface solely depend on overall problem, and does not contain anything that have to do with the design patters. For the the description we have added a property and a predicate:

interface target
    targetProperty : string.
    targetPredicate : ().
end interface target

Likewise the class declaration of the target (here target_1) solely depends on the overall problem:

class target_1 : target
end interface target_1

It will either construct objects of the target type (as above), or of a type that supports target as here:

interface target_2 supports target
% additional special target_2 functionality
end interface target_2
class target_2 : target_2
end interface target_2

The targetSupport and target classes are in symbiosis with one and other:

  • The targetSite interface contains entities that the targetSupport class will need from the target.
  • And the targetSupport interface contains entities that the targetSupport class provides to the target.

The exact contents of these interfaces will depend on how the targetSupport class is supposed to support the construction of the target classes. For the the description we have added a predicate predicate to the targetSite:

interface targetSite
    sitePredicate : ().
end interface targetSite

For the description we will assume that the targetSupport class will directly implement the targetProperty and provide a support predicate, supportPredicate, which the target class can use to implement the targetPredicate.

Since targetProperty is to be exposed directly as target::targetProperty it must be declared as coming from the target interface:

interface targetSupport
properties from target
    supportPredicate : ().
end interface targetSupport

targetSupport'c constructor will (at least) take a targetSite as parameter, here we have also chosen that it should have an initial value for the targetProperty:

class targetSupport : targetSupport
    new : (targetSite Site, string TargetPropertyInit).
end class targetSupport

The implementation of the targetSupport class will store the site in a fact so that the site can be accessed where required. This code also contains example implementation of the targetSupport interface

implement targetSupport
    site : targetSite.
    targetProperty : string.
    new(Site, TargetPropertyInit) :-
        site := Site,
        targetProperty := TargetPropertyInit.
    supportPredicate(...) :-
        site:sitePredicate(),  % site functionality can be used where required
end implement targetSupport

The implementation of the target classes (here target_1) we will inherit from targetSupport to get access to the shared functionality, it will also have to support and implement the targetSite interface and privide itself (i.e. This) as site:

implement target_1 inherits targetSupport % access to shared functionality by inheritance
    supports targetSite % support the site so that the targetSupport can access functionality here
    new(...) :-
        targetSupport::new(This, "target_1_property"). % initialization of the base class
% The targetProperty is directly inherited from the targetSupport
% but this class will have to implement targetPredicate
    targetPredicate() :-
        supportPredicate(),  % we can use the inherited supportPredicate in the target class
    sitePredicate() :- % The target class must implement the sitePredicate
end implement target_1

The support pattern very explicitly express what functionality the support class provides to the target classes and vice versa.

Example The collectionSupport class in PFC is an example of the the support pattern. (Here it is shown in the Visual Prolog 7.5 version.)

A collection must implement this interface:

interface collection{@Type}
    isEmpty : () determ.
    % @short Succeeds if the collection is empty.
    % @end
    contains : (@Type Value) determ.
    % @short Succeeds if the collection contains the value @Type
    % @end
    tryGetFirst : () -> @Type Value determ.
    % @short @Type is the first element in the collection; fails if the collection is empty.
    % @end
    getAll_nd : () -> @Type Value nondeterm.
    % @short @Type is nondeterministic iteration of the elements in the collection.
    % @end
    asList : @Type* (o).
    % @short All the elements in the collection as a list.
    % @end
end interface collection

If the support class have access to the getAll_nd predicate, it can implement all the other predicates in terms of it.

So the site will have to supply getAll_nd predicate:

interface collectionSite{@Type}
predicates from collection{@Type}
end interface collectionSite

And then the support class will implement all the rest:

interface collectionSupport{@Type}
predicates from collection{@Type}
    isEmpty, tryGetFirst
properties from collection{@Type}
end interface collectionSupport

The implementation of the collectionSupport looks like this (here commented additionally):

implement collectionSupport{@Type}
    site : collectionSite{@Type}.
    new(Site) :-
        site := Site.
    isEmpty() :-
        not(_ = site:getAll_nd()).
    tryGetFirst() = First :-
        First = site:getAll_nd(),
    asList() = [ V || V = site:getAll_nd() ].
end implement collectionSupport