OOP prakticky: Substituce

…aneb měníme hodnoty proměnných!
24. 12. 2008

Jak budeme provádět substituci? Jednoduše, musíme v našem výrazu najít všechny proměnné stejného názvu a namísto těchto proměnných vrátit výraz, který je má nahradit. V podstatě na tom nic není. Ještě jedna otázka: budou mít metodu substituce všechny třídy? Vždyť substituovat budeme pouze proměnnou, takže by to svádělo k tomu napsat tuto metodu pouze semka. To by samozřejmě byla chyba. Pokud máme Proměnnou v Součtu, je jasné, že i tato Proměnná musí být nahrazena. Aby tato Proměnná mohla být nahrazena, musíme tu Proměnnou nejprve najít. To uděláme nejjednodušeji tak, že zavoláme metodu Substituce() u Součtu a ta zavolá metodu Substituce() jak na výraz A, tak na výraz B. Tím dosáhneme toho, že ať budeme třeba stovky zanořených Součtů, nakonec se dostaneme ke všech výrazům a všechny zkontrolujeme, jestli se náhodou nejedná o Proměnnou, kterou hledáme. Takže odpověď na původní otázku zní, že metodu Substituce() bude mít každý Matematický Výraz. Tam ji také definujeme.

   1: abstract class MatematickyVyraz
   2: {
   3:     public abstract MatematickyVyraz Derivace();
   4:     public abstract MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota);
   5:     public abstract MatematickyVyraz Kopie();
   6: }

Metoda bude mít dva argumenty: String reprezentující Název Proměnné, kterou hledáme a Matematický Výraz, kterým chceme nahrazovat. Implementace v jednotlivých třídách již bude triviální. Připomínám, že metoda bude vracet nový Matematický Výraz, takže v každém kroku musím vytvářet nové kopie objektů. Konstanta:

   1: public override MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota)
   2: {
   3:     return Kopie();
   4: }

Konstantu zřejmě nijak substituovat nemůžeme, vrátíme proto pouze kopii. Implementace v Proměnné:

   1: public override MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota)
   2: {
   3:     if(Nazev == NazevPromenne)
   4:         return Hodnota;
   5:     else
   6:         return Kopie();
   7: }

Nejprve zjistíme, jestli jsme našli proměnnou, kterou hledáme. Pokud ano, vrátíme předaný Matematický Výraz. Pokud ne, vrátíme také pouze kopii Proměnné. U Binárních výrazů bude situace stejná – vytvoříme vždy novou instanci daného výrazu a na vlastnosti A a B poštveme substituci. Implementace u Součtu:

   1: public override MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota)
   2: {
   3:     Soucet soucet = new Soucet();
   4:  
   5:     soucet.A = A.Substituce(NazevPromenne, Hodnota);
   6:     soucet.B = B.Substituce(NazevPromenne, Hodnota);
   7:  
   8:     return soucet;
   9: }

Rozdíl:

   1: public override MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota)
   2: {
   3:     Rozdil rozdil = new Rozdil();
   4:  
   5:     rozdil.A = A.Substituce(NazevPromenne, Hodnota);
   6:     rozdil.B = B.Substituce(NazevPromenne, Hodnota);
   7:  
   8:     return rozdil;
   9: }

Součin:

   1: public override MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota)
   2: {
   3:     Soucin soucin = new Soucin();
   4:  
   5:     soucin.A = A.Substituce(NazevPromenne, Hodnota);
   6:     soucin.B = B.Substituce(NazevPromenne, Hodnota);
   7:  
   8:     return soucin;
   9: }

Podíl:

   1: public override MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota)
   2: {
   3:     Podil podil = new Podil();
   4:  
   5:     podil.A = A.Substituce(NazevPromenne, Hodnota);
   6:     podil.B = B.Substituce(NazevPromenne, Hodnota);
   7:  
   8:     return podil;
   9: }

A to je všechno. Vyzkoušíme.

   1: static void Main(string[] args)
   2: {
   3:     Konstanta a = new Konstanta(10);
   4:     Konstanta b = new Konstanta(20);
   5:  
   6:     Promenna x = new Promenna("x");
   7:     Promenna y = new Promenna("y");
   8:  
   9:     Soucet soucet = new Soucet(a, x);
  10:     Soucin soucin = new Soucin(b, y);
  11:  
  12:     Rozdil rozdil = new Rozdil(soucet, soucin);
  13:  
  14:     Console.WriteLine("Před substitucí: {0}", 
  15:         rozdil.ToString());
  16:  
  17:     Console.WriteLine("Po substituci [x => 666]: {0}", 
  18:         rozdil.Substituce("x", new Konstanta(666)).ToString());
  19:  
  20:     Console.WriteLine("Po substituci [x => 666; y => 33]: {0}", 
  21:         rozdil.Substituce("x", new Konstanta(666)).Substituce("y", new Konstanta(33)).ToString());
  22:  
  23:     Console.WriteLine("Po substituce [x => (10 + 20)]: {0}", 
  24:         rozdil.Substituce("x", new Soucet(a, b)).ToString());
  25:  
  26:     Console.Read();
  27:  
  28:     /*
  29:     Výstup z programu:
  30:     
  31:     Před substitucí: ((10 + x) - (20 * y))
  32:     Po substituci [x => 666]: ((10 + 666) - (20 * y))
  33:     Po substituci [x => 666; y => 33]: ((10 + 666) - (20 * 33))
  34:     Po substituce [x => (10 + 20)]: ((10 + (10 + 20)) - (20 * y))
  35:     */
  36: }