HTML

Projektmenedzsment, alkalmazásfejlesztés

Online projektmenedzsment rendszerek, webes alkalmazások fejlesztése, refactoring.

Friss topikok

Linkblog

A paraméterátadás egyszerűsítése a paraméterek számának csökkentésével (1. rész)

2011.02.05. 15:27 develop

Az üzleti logika megvalósítása során a gyakran használt algoritmus-részeket függvényekbe, még inkább osztályok metódusaiba gyűjtjük.

Az újrahasznosítás során az osztály metódusainak (szolgáltatásainak) hívásával "egyszerűsítjük" a kódunkat (lévén egy több lépéses algoritmus helyett csupán egy hívást illesztünk a kódba).

A módszer lényege, hogy csökkentsük az átadott paraméterek számát: csak azt hagyjuk benne, ami feltétlenül szükséges a feladat elvégzéséhez.

Célunk egy érthetőbb és áttekinthetőbb kód létrehozása az igények alapján.

Az átalakítást célszerű olyan metódussal kezdeni, amit:

  • gyakran hívunk,
  • módosítani, továbbfejleszteni kell,
  • összetett feladatot lát el, amiből egy/több feladatot másik helyen is fel kell használnunk,
  • stb.

Példa, kép feliratozása

Az alábbi PHP példa során mutatom be a módszer lépéseit.

(Nem cél egy teljes, mindenre kiterjedő megoldás bemutatása, mivel az átalakítás lehetőségei, lépései nagymértékben függnek az igényektől, a metódus és a környezet feladatától, stb.)

Az üzleti logika alapján JPG formátumú képre kell szöveget írnunk, a kép bal és felső szélétől adott, egyenlő távolságra.

Az előkészületek érdekében vegyünk egy JPG állományt (mintakep.jpg), illetve egy fontot (arial.ttf). (A példa érdekében mindkét állományt a C gyökerében helyeztem el.)

(Hogy ne érjen minket meglepetés, célszerű a magyar ABC minden betűjét tartalmazó szöveget írni a képre. A "Hello world!" itt most kevésbé hasznos. :)

A kezdeti forrásunk.

$image = imagecreatefromjpeg( 'c:\mintakep.jpg' );
$colorWhite = imagecolorallocate( $image, 255, 255, 255 );

$font = 'c:\arial.ttf';
$text = 'árvíztűrő tükörfúrógép ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP';

imagettftext( $image, 12, 0, 4, 16, $colorWhite, $font, $text );

imagejpeg( $image,'c:\mintakep_output.jpg' );

(Mindenkitől elnézést a minták esetleg elcsúszó tabuláltsága miatt. Kiemeléssel igyekeztem szemléltetni a kód módosulásait, sajnos ez kód-struktúra kárára ment. Ennyit sikerült kihozni a WYSIWYG/HTML szerkesztőből.)

A fenti példában az imagettftext alap PHP függvény végzi a szöveg kiírását a képre. Látható, hogy a paraméterek átadása nem túl beszédes.

A nevesített paraméterekről van sejtésünk, milyen feladatot látnak el. A többi esetében viszont csak tippelhetünk; bővebb felvilágost csak a manual ad.

Az igények alapján a paraméterek nagy részére nincs szükségünk.

(További probléma, hogy a fenti megoldás egyáltalán nem rugalmas. Másik kép feliratozása, több szöveg elhelyezése - bár megoldható -, mégis macerás. Nem tudjuk újrahasznosítani a kódot, nehezen tesztelhető, stb.)

Osztály létrehozása

Első lépésben készítsünk egy osztályt (pl. myImage néven), az imagettftext-et pedig helyezzük a write metódusba; ez fogja elvégezni a képre írást.

class myImage {
  public function write( &$image, $size, $angle, $x, $y, $color, $fontfile, $text ) {
    imagettftext( $image , $size, $angle, $x, $y, $color, $fontfile, $text );
  }
}

$myImage = new myImage();
$image = imagecreatefromjpeg( 'c:\mintakep.jpg' ); $colorWhite = imagecolorallocate( $image, 255, 255, 255 ); $fontfile = 'c:\arial.ttf'; $text = 'árvíztűrő tükörfúrógép ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP'; $myImage -> write( $image, 12, 0, 4, 16, $colorWhite, $fontfile, $text ); imagejpeg( $image, 'c:\mintakep_output.jpg' );

Az új metódus paramétereiben használjunk beszédes paraméter neveket. (Javaslom, hogy vegyük alapul a PHP manualban használt elnevezéseket. További elnevezési ajánlások: változó, metódus, osztály.)

Attribútumok számának további csökkentése

Emeljük be az osztályba azokat az attribútumokat, amiket - jelen példa során - nem akarunk módosítani, ilyen pl. a betűtípus is.

Mivel ezek az attribútumok már az osztály részei, fel tudjuk használni az osztályon belül; így egy paraméterrel már rövidebb a hívás és a write metódus is.

class myImage {
  const fontfile = 'c:\arial.ttf';
  public function write( &$image, $size, $angle, $x, $y, $color, $text ) {
    imagettftext( $image , $size, $angle, $x, $y, $color, self::fontfile, $text );
  }
} $myImage = new myImage(); $image = imagecreatefromjpeg( 'c:\mintakep.jpg' ); $colorWhite = imagecolorallocate( $image, 255, 255, 255 ); $text = 'árvíztűrő tükörfúrógép ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP'; $myImage -> write( $image, 12, 0, 4, 16, $colorWhite, $text ); imagejpeg( $image,'c:\mintakep_output.jpg' );

Egyszerűsítések az igények alapján

Annak érdekében, hogy már a példányosításkor - kötelezően - meg tudjunk adni egy forrás képet, a konstruktorba helyezzük ennek a lehetőségét.

Mivel sem a felirat színét sem pedig a szöget nem akarjuk módosítani, így ezek megadását is kivehetjük.

class myImage {
  const fontfile = 'c:\arial.ttf';
  public $image = null;
  public $color = null;
  public $angle = 0;
  protected $imageFilePathSource = null;

  function __construct( $imageFilePathSource ) {
    $this -> imageFilePathSource = $imageFilePathSource;
    $this -> image = imagecreatefromjpeg( $this -> imageFilePathSource );
    $this -> color = imagecolorallocate( $this -> image, 255, 255, 255 );
}

  public function write( &$image, $size, $x, $y, $text ) {
    imagettftext( $image , $size, $this -> angle, $x, $y, $this -> color, self::fontfile, $text );
  }
} $myImage = new myImage( 'c:\mintakep.jpg' ); $text = 'árvíztűrő tükörfúrógép ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP'; $myImage -> write( $myImage -> image, 12, 4, 16, $text ); imagejpeg( $myImage -> image,'c:\mintakep_output.jpg' );

További egyszerűsítések

Mivel nem akarunk több különféle méretű feliratot készíteni - de egy alap méretet azért mégis csak szeretnénk megadni -, a lehetőséget a konstruktorban adjuk meg, ugyanakkor egy default szöveg méretet is definiálunk, ha a példányosításkor nem adnánk meg semmilyen értéket.

Eltávolítottam a $text változót is, betettem a hívásba. Itt feleslegesnek tűnik egy külön változót fenntartani a szövegnek.

class myImage {
  const fontfile = 'c:\arial.ttf';
  
  public $image = null;
  
  public $color = null;
  
  public $angle = 0;
  
  const sizeDefault = 12;   public $size = self::sizeDefault;
  
  protected $imageFilePathSource = null;
  
  function __construct( $imageFilePathSource, $size = null ) {
    $this -> imageFilePathSource = $imageFilePathSource;
    
    $this -> image = imagecreatefromjpeg( $this -> imageFilePathSource );
    
    $this -> color = imagecolorallocate( $this -> image, 255, 255, 255 );
    
    if( !is_null( $size ) ) {
     $this -> size = $size;     }
  }   function write( &$image, $x, $y, $text ) {
    imagettftext( $image , $this -> size, $this -> angle, $x, $y, $this -> color, self::fontfile, $text );   }
} $myImage = new myImage( 'c:\mintakep.jpg', 12 ); $myImage -> write( $myImage -> image, 4, 16, 'árvíztűrő tükörfúrógép ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP' ); imagejpeg( $myImage -> image,'c:\mintakep_output.jpg' );

A kép mentése

Már csak a kép mentése van hátra, amit a kimeneti állománynév megadásával tudunk meghívni.

class myImage {
  const fontfile = 'c:\arial.ttf';
    
  public $image = null;
  
  public $color = null;
  
  public $angle = 0;
  
  const sizeDefault = 12;
  public $size = self::sizeDefault;
  
  protected $imageFilePathSource = null;
  
  function __construct( $imageFilePathSource, $size = null ) {
    $this -> imageFilePathSource = $imageFilePathSource;
    
    $this -> image = imagecreatefromjpeg( $this -> imageFilePathSource );
    
    $this -> color = imagecolorallocate( $this -> image, 255, 255, 255 );
    
    if( !is_null( $size ) ) {
      $this -> size = $size;
    }
  }
  
  public function write( $x, $y, $text ) {
    imagettftext( $this -> image , $this -> size, $this -> angle, $x, $y, $this -> color, self::fontfile, $text );
  }
  
   public function save( $imageFilePathDestination ) {     imagejpeg( $this -> image, $imageFilePathDestination );
  }
} $myImage = new myImage( 'c:\mintakep.jpg', 12 ); $myImage -> write( 4, 16, 'árvíztűrő tükörfúrógép ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP' ); $myImage -> save( 'c:\mintakep_output.jpg' );

Láthatóságok aktualizálása

Ezzel tulajdonképpen megvagyunk, tiszta kódot kaptunk a refactoring lépéseivel.

Az osztályunk ugyanakkor nem teljesíti az egységbezárás feltételeit, mivel többet mutat magából, mint amennyit feltétlenül szükséges lenne. A változók kívülrők elérhetőek, módosíthatóak.

Rejtsük el a változókat, hogy az osztály tudta és felügyelete nélkül ne lehessen őket módosítani. Célszerű ilyenkor a legszigorúbban eljárni.

class myImage {
  const fontfile = 'c:\arial.ttf';
  
  protected $image = null;
  
  protected $color = null;
  
  protected $angle = 0;
  
  const sizeDefault = 12;
  protected $size = self::sizeDefault;
  
  protected $imageFilePathSource = null;
  
  function __construct( $imageFilePathSource, $size = null ) {
    $this -> imageFilePathSource = $imageFilePathSource;
    
    $this -> image = imagecreatefromjpeg( $this -> imageFilePathSource );
    
    $this -> color = imagecolorallocate( $this -> image, 255, 255, 255 );
    
    if( !is_null( $size ) ) {
      $this -> size = $size;
    }
  }
  
  public function write( $x, $y, $text ) {
    imagettftext( $this -> image , $this -> size, $this -> angle, $x, $y, $this -> color, self::fontfile, $text );
  }
  
  public function save( $imageFilePathDestination ) {
    imagejpeg( $this -> image, $imageFilePathDestination );
  }
}

$myImage = new myImage( 'c:\mintakep.jpg', 12 );
$myImage -> write( 4, 16, 'árvíztűrő tükörfúrógép ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP' );
$myImage -> save( 'c:\mintakep_output.jpg' );

Adott távolságra a szélektől

Ebben a lépésben valósítottam meg, hogy csak a bal felső szélektől adott távolságra tudjunk írni: elrejtem a write metódust, és writeLeftTop néven bevezetek egy új metódust.

Annak érdekében, hogy azért mégis csak egyszerűen legyen lehetőségünk több képet is feliratozni, a konstruktorban található kódrészletet metódusba emeltem ki. (Ebben a példában kelleni fog egy mintakep2.jpg is.)

(Hogy az átalakítás bemutatását ne zavarják, a végére hagytam a kommentezést.)

class myImage {
  const fontfile = 'c:\arial.ttf';
  
  protected $image = null;
  
  protected $color = null;
  
  protected $angle = 0;
  
  const sizeDefault = 12;
  protected $size = self::sizeDefault;
  
  protected $imageFilePathSource = null;
  
  /**
   * A forrás állomány megadása a teljes elérési úttal.
   * 
   * @param string Az állomány teljes elérési útja.
   */
  public function setImageFilePathSource( $imageFilePathSource = null ) {
    if( is_null( $imageFilePathSource ) ) {
      return;
    }
  
    $this -> imageFilePathSource = $imageFilePathSource;
    
    $this -> image = imagecreatefromjpeg( $this -> imageFilePathSource );
    
    $this -> color = imagecolorallocate( $this -> image, 255, 255, 255 );
  }
  
  /**
   * 
   * @param string A forrás állomány teljes elérési útja.
   * @param int A szöveg mérete
   */
  function __construct( $imageFilePathSource = null, $size = null ) {
    $this -> setImageFilePathSource( $imageFilePathSource );

    if( !is_null( $size ) ) {
      $this -> size = $size;
    }
  }
  
  /**
   * A szöveg méretének beállítása
   * 
   * @param int Méret
   */
  public function setSize( $size ) {
    $this -> size = $size;
  }
  
  /**
   * Szöveg írása a képre; a bal felső sarok koordinátája: (x, y) = (0, 0)
   * 
   * @param int A szöveg megjelenésének X pozíciója
   * @param int A szöveg megjelenésének Y pozíciója
   * @param string A szöveg
   */
  protected function write( $x, $y, $text ) {
    imagettftext( $this -> image , $this -> size, $this -> angle, $x, $y, $this -> color, self::fontfile, $text );
  }
  
  /**
   * Kép bal felső sarkába szöveg írása
   * 
   * @param string A szöveg
   * @param int Távolság a kép széleitől
   */
   public function writeLeftTop( $text, $delta = 0 ) {
    $this -> write( $delta, $this -> size + $delta, $text );
  }
/** * Kép mentése a megadott kimeneti állományba * * @param string A kimeneti állomány teljes elérési útja */ public function save( $imageFilePathDestination ) { imagejpeg( $this -> image, $imageFilePathDestination ); } } $myImage = new myImage(); $myImage -> setSize( 12 ); $myImage -> setImageFilePathSource( 'c:\mintakep.jpg' ); $myImage -> writeLeftTop( 'árvíztűrő tükörfúrógép ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP', 4 ); $myImage -> save( 'c:\mintakep_output.jpg' ); $myImage -> setImageFilePathSource( 'c:\mintakep2.jpg' ); $myImage -> writeLeftTop( 'árvíztűrő tükörfúrógép ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP', 4 ); $myImage -> save( 'c:\mintakep_output2.jpg' );

Igaz, hogy a kezdeti 9 sorból majd 100 soros kód lett, de a kapott előnyök - azt gondolom -, kárpótolják a befektetett munkát.

A refactoringnak alávetett kód áttekinthetőbb, a változó/bővülő igyényekre rugalmasabban felkészíthető.

Szólj hozzá!

Címkék: refactoring tiszta kód paraméterátadás egyszerűsítése

A bejegyzés trackback címe:

https://develop.blog.hu/api/trackback/id/tr582640266

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása