Guardian (suunnittelukuvio)
Keeper ( eng. Memento ) on käyttäytymismuotoilumalli , joka sallii kapselointia rikkomatta korjata ja tallentaa kohteen sisäisen tilan, jotta se voidaan palauttaa tähän tilaan myöhemmin.
Tälle mallille on kaksi mahdollista toteutusta: klassikko, joka on kuvattu kirjassa Design Patterns , ja harvinaisempi epästandardi versio.
Sovellus
Guardian-mallia käytetään, kun:
- on tarpeen tallentaa tilannekuva kohteen (tai sen osan) tilasta myöhempää palauttamista varten
- suora käyttöliittymä objektin tilan selvittämiseksi paljastaa toteutuksen yksityiskohdat ja katkaisee objektin kapseloinnin
Rakenne
Klassinen variantti:
Epätyypillinen vaihtoehto:
- Aloittaja - "Luoja"
- Talonmies - "Vartija"
- Memento - "Keeper"
Kuvaus
Klassinen muunnelma: Guardian-kuviota käyttävät kaksi objektia: "Creator" (alkuperäinen) ja "Guardian" (vartija). "Luoja" on esine, jolla on sisäinen tila. "Guardian"-objekti voi suorittaa joitain toimintoja "Luojan" kanssa, mutta samalla on voitava peruuttaa muutokset. Tätä varten Guardian pyytää Guardian-objektia Luojalta. Suorittaa sitten suunnitellun toiminnon (tai toimintosarjan). Palauttaakseen "Luojan" muutoksia edeltäneeseen tilaan "Guardian" palauttaa "Keeper"-objektin "Luojalle". "Suojelija" on läpinäkymätön (eli sellainen, jota "Vartija" ei voi tai ei saa muuttaa).
Epätyypillinen variantti: Tämän muunnelman ero klassiseen on "Suojelijan" pääsyn "Luojan" sisäiseen tilaan ankarammassa rajoituksessa. Klassisessa versiossa "Guardian" voi päästä käsiksi "Luojan" sisäisiin tietoihin "Keeperin" kautta, muuttaa tilaa ja asettaa sen takaisin "Luojaksi". Tässä versiossa "Guardian" voi vain palauttaa "Guardian" tilan soittamalla Restore. Muun muassa "Suojelijan" ei tarvitse omistaa yhteyttä "Vartijaan" palauttaakseen tilansa. Tämän avulla voit tallentaa ja palauttaa monimutkaisten hierarkkisten tai verkkorakenteiden tilan (objektien tilan ja kaikkien niiden välisten suhteiden) keräämällä tilannekuvia kaikista järjestelmän rekisteröidyistä objekteista.
Toteutusesimerkkejä
Tavallinen Java-malli
Java lähde
public class Memento {
yksityinen lopullinen merkkijonon tila ;
public Memento ( merkkijonon tila ) {
this . tila = tila ;
}
public String getState ( ) {
paluutila ; } }
julkinen luokka Talonmies {
yksityinen Muistomuisto ; _
public Memento getMemento () {
return muisto ;
}
public void setMemento ( Memento memento ) {
this . muisto = muisto ;
}
}
public class Alkuperäinen {
yksityinen merkkijonon tila ;
public void setState ( merkkijonon tila ) {
this . tila = tila ;
}
public String getState ( ) {
paluutila ; }
public Memento saveState () {
return new Memento ( tila );
}
public void restoreState ( Memento memento ) {
this . tila = muisti . getstate ();
}
}
public class Sovellus {
public static void main ( Merkkijono [] args ) {
Alkuperäinen kirjoittaja = uusi Alkuperäinen ( ); Talonmies talonmies = uusi Talonmies ();
alullepanija . setState ( "on" );
Järjestelmä . ulos . printf ( "Tila on %s\n" , alkuperäinen . getState ());
talonmies . setMemento ( originator.saveState ( ) );
alullepanija . setState ( "off" );
Järjestelmä . ulos . printf ( "Tila on %s\n" , alkuperäinen . getState ());
alullepanija . restoreState ( caretaker.getMemento ( ) ); Järjestelmä . ulos . printf ( "Tila on %s\n" , alkuperäinen . getState ()); } }
/*
* Lähtö:
* Tila on päällä
* Tila on pois päältä
* Tila on päällä
*/
PHP5-oletusmalli
PHP5 lähdekoodi
<?php
/**
* Keeper-malli tallentaa ja palauttaa objektien tilat
*/
nimiavaruus Memento {
/**
* Creator tallentaa ja palauttaa sisäisen tilan
*/
class Originator {
yksityinen $valtio ;
public function setState ( $tila ) {
$this -> state = $state ;
echo sprintf ( "Tilajoukko %s \n " , $this -> tila );
}
public function getState () {
return $this -> state ;
}
/**
* Luo tilannekuva objektin tilasta
* @return Memento
*/
public function saveMemento () {
return new Memento ( $this -> state );
}
/**
* Palautustila
* @param \Memento\Memento $memento
*/
public function returnMemento ( Memento $memento ) {
echo sprintf ( "Palautetaan tilaa... \n " );
$this -> state = $muisto -> getState ();
}
}
/**
* Tilannekuva
*/
luokan muisto {
yksityinen $valtio ;
julkinen funktio __konstrukti ( $tila ) {
$this -> state = $tila ;
}
public function getState () {
return $this -> state ;
}
}
/**
* Kohteen tilan huoltaja
* /
class Hoitaja {
yksityinen $muisto ;
public function getMemento () {
return $this -> memento ;
}
public function setMemento ( Memento $muisto ) {
$this -> memento = $muisto ;
}
}
$alkuperäinen = uusi Alkuperäinen ();
$alkuperäinen -> setState ( "Päällä" );
// Tallenna sisäinen tila
$caretaker = new Caretaker ();
$caretaker -> setMemento ( $alkuperäinen -> saveMemento ());
// Jatka lähettäjän vaihtamista
$originator -> setState ( "Off" );
// Palauta tallennettu tila
$originator -> restoreMemento ( $caretaker -> getMemento ());
}
C#-mallin ensimmäinen versio
Lähdeteksti
C#
//Tämä rakennekoodi näyttää Memento-mallin, joka väliaikaisesti tallentaa ja palauttaa toisen objektin sisäisen tilan.
// Muistokuvio -- Rakenneesimerkki
käyttäen System ;
nimitila DoFactory.GangOfFour.Memento.Structural
{
/// <summary>
/// MainApp-käynnistysluokka Structuralille
/// Memento Design Pattern.
/// </summary>
luokka MainApp
{
/// <summary>
/// Pääsypiste konsolisovellukseen.
/// </summary>
static void Main ()
{
Alkuperäinen o = uusi Alkuperäinen ();
o . Tila = "Päällä" ;
// Tallenna sisäinen tila
Caretaker c = new Careker ();
c . Muisto = o . LuoMemento ();
// Jatka lähettäjän
o vaihtamista . Tila = "Pois" ;
// Palauta tallennettu tila
o . SetMemento ( c . Memento );
// Odota käyttäjän
konsolia . ReadKey ();
}
}
/// <summary>
/// Alkuperäinen luokka
/// </summary>
class Alkuperäinen
{
yksityinen merkkijono _tila ;
// Omaisuuden
julkinen merkkijono Tila
{
get { return _state ; }
set
{
_tila = arvo ;
konsoli . WriteLine ( "Tila = " + _tila );
}
}
// Luo muiston
public Memento CreateMemento ()
{
return ( new Memento ( _state ));
}
// Palauttaa alkuperäisen tilan
public void SetMemento ( Memento memento )
{
Konsoli . WriteLine ( "Palautetaan tilaa..." );
tila = muisto . valtio ;
}
}
/// <summary>
/// 'Memento'-luokka
/// </summary>
class Memento
{
yksityinen merkkijono _tila ;
// Rakentaja
public Memento ( merkkijonon tila )
{
this . _tila = tila ;
}
// Hakee tai asettaa tilan
public string Tila
{
get { return _state ; }
}
}
/// <summary>
/// 'Huomio'-luokka
/// </summary>
luokka Talonmies
{
private Memento _memento ;
// Hakee tai asettaa mementon
public Memento Memento
{
set { _memento = arvo ; }
get { return _muistomerkki ; }
}
}
}
Lähtötila
= Päällä Tila = Pois Palautustila : Tila = Päällä _ _
C#
Lähdeteksti
C#
käyttäen System ;
nimitila MementoPatte
{
luokka Ohjelma
{
staattinen void Main ( merkkijono [] args )
{
Foo foo = new Foo ( "Testi" , 15 );
foo . tulostaa ();
Talonmies ct1 = uusi Talonmies ();
Talonmies ct2 = uusi Talonmies ();
ct1 . SaveState ( foo );
foo . IntProperty += 152 ;
foo . tulostaa ();
ct2 . SaveState ( foo );
ct1 . RestoreState ( foo );
foo . tulostaa ();
ct2 . RestoreState ( foo );
foo . tulostaa ();
konsoli . ReadKey ();
}
}
julkinen käyttöliittymä IOriginator
{
object GetMemento ();
void SetMemento ( objekti muisto );
}
public class Foo
: IOriginator
{
julkinen merkkijono StringProperty
{
get ;
yksityinen sarja ;
}
public int IntProperty
{
get ;
asettaa ;
}
public Foo ( merkkijono stringPropertyValue , int intPropertyValue = 0 )
{
StringProperty = stringPropertyValue ;
IntProperty = intPropertyValue ;
}
public void Tulosta ()
{
Konsoli . WriteLine ( "==============" );
konsoli . WriteLine ( "StringProperty arvo: {0}" , StringProperty );
konsoli . WriteLine ( "IntProperty-arvo: {0}" , IntProperty );
konsoli . WriteLine ( "==============" );
}
objektin IOriginator . GetMemento ()
{
return new Memento { StringProperty = this . StringProperty , IntProperty = tämä . IntProperty };
}
tyhjä IOriginator . SetMemento ( objekti muisto )
{
if ( Object . ReferenceEquals ( memento , null ))
throw new ArgumentNullException ( " memento " );
if (!( memento on Memento ))
heittää uusi ArgumentException ( "muisto" );
StringProperty = (( Memento ) muisto ). StringProperty ;
IntProperty = (( Memento ) muisto ). IntProperty ;
}
class Memento
{
julkinen merkkijono StringProperty
{
get ;
asettaa ;
}
public int IntProperty
{
get ;
asettaa ;
}
}
}
public class Talonmies
{
yksityinen objekti m_muisto ;
public void SaveState ( IOriginator originator )
{
if ( aloittaja == null ) throw new ArgumentNullException ( " alkuperäinen " ); m_memento = kirjoittaja . GetMemento (); }
public void RestoreState ( IOriginator originator )
{
if ( aloittaja == null ) throw new ArgumentNullException ( " alkuperäinen " ); if ( m_memento == null ) heittää uusi InvalidOperationException ( "m_memento == null" ); alullepanija . SetMemento ( m_memento ); } } }
Mukautettu malli
Lähdeteksti
C#
käyttäen System ;
käyttäen System.Collections.Generic ;
julkinen käyttöliittymä IOriginator
{
IMemento GetState ();
}
julkinen käyttöliittymä IShape : IOriginator
{
void Draw ();
voidScale ( doublescale ) ; _ void Move ( double dx , double dy ); }
julkinen käyttöliittymä IMemento
{
void RestoreState ();
}
julkinen luokka CircleOriginator : IShape
{
yksityinen luokka CircleMemento : IMemento
{
yksityinen vain luku double x ;
yksityinen vain luku double y ;
yksityinen vain luku double r ;
yksityinen vain lukuoikeus CircleOriginatorin kirjoittaja ;
public CircleMemento ( CircleOriginatorin kirjoittaja )
{
this . aloittaja = aloittaja ;
x = aloittaja . x ;
y = aloittaja . y ;
r = aloittaja . r ;
}
public void RestoreState ()
{
alkuperäinen . x = x ;
alullepanija . y = y_ _
alullepanija . r = r ;
}
}
tupla x ;
kaksinkertainen y ;
kaksinkertainen r ;
public CircleOriginator ( double x , double y , double r )
{
this . x = x ;
tämä . y = y_ _
tämä . r = r ;
}
public void Piirrä ()
{
Konsoli . WriteLine ( "Ympyrä, jonka säde on {0} kohdassa ({1}, {2})" , r , x , y );
}
public void Asteikko ( kaksoisasteikko ) { r * = asteikko ; }
public void Siirrä ( double dx , double dy )
{
x += dx ;
y += dy ;
}
public IMemento GetState ()
{
return new CircleMemento ( tämä );
}
}
public class RectOriginator : IShape
{
yksityinen luokka RectMemento : IMemento
{
yksityinen vain luku double x ;
yksityinen vain luku double y ;
yksityinen vain luku double w ;
yksityinen vain luku kaksinkertainen h ;
yksityinen vain luku RektOriginator kirjoittaja ;
public RectMemento ( RectOriginator - lähde )
{
this . aloittaja = aloittaja ;
x = aloittaja . x ;
y = aloittaja . y ;
w = aloittaja . w _
h = aloittaja . h _
}
public void RestoreState ()
{
alkuperäinen . x = x ;
alullepanija . y = y_ _
alullepanija . w = w _
alullepanija . h = h ;
}
}
tupla x ;
kaksinkertainen y ;
kaksinkertainen w ;
kaksinkertainen h ;
public RectOriginator ( double x , double y , double w , double h )
{
this . x = x ;
tämä . y = y_ _
tämä . w = w _
tämä . h = h ;
}
public void Piirrä ()
{
Konsoli . WriteLine ( "Suorakaide {0}x{1} kohdassa ({2}, {3})" , w , h , x , y );
}
public void Asteikko ( kaksoisasteikko ) { w * = asteikko ; h *= asteikko ; }
public void Siirrä ( double dx , double dy )
{
x += dx ;
y += dy ;
}
public IMemento GetState ()
{
return new RectMemento ( tämä );
}
}
public class Hoitohenkilö
{
julkinen staattinen void Piirrä ( IEnumerable < IShape > muodot )
{
foreach ( ISmuoto muoto muodoissa ) { muoto . _ piirtää (); } }
public static void MoveAndScale ( IEnumerable < IShape > muodot )
{
foreach ( ISmuoto muoto muodoissa ) { muoto . _ mittakaava ( 10 ); muoto . Siirrä ( 3 , 2 ); } }
public static IEnumerable < IMemento > SaveStates ( IEnumerable < IShape > muodot )
{
LinkedList < IMemento > states = new LinkedList < IMemento >();
foreach ( ISmuoto muoto muodoissa ) { tilat . _ AddLast ( shape.GetState ( ) ); } paluutilat ; _ }
public static void RestoreStates ( IEnumerable < IMemento > states )
{
foreach ( IMemento tila tiloissa ) { tila . _ RestoreState (); } }
public static void Main ()
{
IShape [] muodot = { new RectOriginator ( 10 , 20 , 3 , 5 ), new CircleOriginator ( 5 , 2 , 10 ) };
//Tulokset:
// Suorakulmio 3x5 kohdassa (10, 20)
// Ympyrä, jonka säde on 10 kohdassa (5, 2)
Piirrä ( muodot );
//Tallenna muotojen tilat
IEnumerable < IMemento > states = SaveStates ( muodot );
//Muovien paikan muuttaminen
MoveAndScale ( muodot );
//Tulokset:
// Suorakaide 30x50 kohdassa (13, 22)
// Ympyrä, jonka säde on 100 kohdassa (8, 4)
Piirrä ( muodot );
//Palauta muotojen vanha sijainti
RestoreStates ( states );
//Tulokset:
// Suorakulmio 3x5 kohdassa (10, 20)
// Ympyrä, jonka säde on 10 kohdassa (5, 2)
Piirrä ( muodot );
}
}
Epätyypillinen C++-malli
Lähdeteksti
C++ :ssa
# sisältää <iostream>
käyttäen nimiavaruutta std ;
luokan aloittaja {
int tila ;
julkinen :
alullepanija ();
luokkamuisto ; _
Memento * getMemento ();
void setState ( int );
void dumpState ();
luokan muisto {
ystäväluokka Aloittelija ; _
yksityinen :
int tila ;
alullepanija * org ;
julkinen :
muisto ();
void returnState ();
};
};
alullepanija :: alullepanija () : tila ( 0 ) {
}
void Originator :: setState ( int s ) {
tila = s ;
}
void Originator :: dumpState () {
cout << "Tila: " << tila << endl ;
}
Alkuperäinen :: Muisto :: Muisto () : tila ( 0 ) {
}
Kirjoittaja :: Memento * Alkuperäinen :: getMemento () {
Alkuperäinen :: Muisto * m = uusi Alkuperäinen :: Muisto ();
m -> org = tämä ;
m -> tila = tila ;
paluu m ;
}
void Alkuperäinen :: Muisto :: returnState () {
org -> tila = tila ;
}
int main ( void ) {
alullepanija org ;
org . setState ( 1 );
org . kaatopaikka ();
Alkuperäinen :: Memento * m1 = org . getMemento ();
org . setState ( 2 );
org . kaatopaikka ();
m1 -> palautustila ();
org . kaatopaikka ();
poista m1 ;
}
Linkit