7

Aprill

Iluvõtted koodile I

Marek Tihkan 3 kommentaari

brokkoliIlusa koodi saamiseks ei ole vaja toita teda brokkoliga, osta kalleid kreeme ega noorenevaid tablette. Tegelikult on olemas küllaltki lihtsaid võtteid selle saamiseks. Peamiselt on need tulnud sisemiste Domain Specific Language (DSL) loomise võtetest, õigemini sinna poole pürgimegi ehk kood näeks välja nagu DSL.

Esimeseks võtteks, mida käsitlen, on laiendusmeetodite (Extension Methods) kasutamine. Nende abiga saame kergesti olemasolevatele klassidele lisada meetodeid juurde, eriti kui meil pole võimalik klassi ennast muuta.

Esimene näitena toon keeleliste struktuuride ilustamisest. Suhteliselt harva kasutan for tsüklit, mistõttu pole see konstruktsioon väga selgelt enam mu peas (ajan pidevalt segamini, kas on “,” või “;” osade vahel). Lisaks tuleb alati seda pikalt lugeda, et aru saada, mis seal tehakse. Palju selgemini väljendub laiendusmeetodite abiga tehtud funktsioon:

for (var index = 0; index < 5; index++)
{
  //...
}

// vs

5.Times(index =>
{
   //…
});

Realiseerimiseks läheb vaja mõnerealist koodi:

public static void Times(this int count, Action<int> action)
{
  if (count < 0)
    throw new ArgumentException("Count should be positive");
  for (var index = 0; index < count; index++)
    action(index);
}

Laiendusmeetodid on osutunud kasulikuks ka arvutuste sõnastamisel. Näiteks:

Time.AddDays(1);
new DateTime(Time.Year, Time.Month, DateTime.DaysInMonth(Time.Year, Time.Month))

Time.Tommorrow();
Time.EndOfMonth();

Viimased read on palju selgemini väljendatud ning ei vaja mõttetööd koodi lugemisel.

Abiks on olnud laiendusmeetodid ka teisendamistel. Eriti kui üle süsteemi kasutan ühte väärtust mõnel argumendil.

new Money(90.5m, Currency.EEK)

90.5m.AsMoney();

Vahel aitavad need lisada juurde ka konteksti:

5.Percent();

Laiendusmeetodid võivad arhitektuurilist piltiki veidi muuta – paljud kasutavad Active Record mustrit ning tüüpiliselt on see realiseeritud nii, et peame mõne raamistiku baasklassist pärinema. See on tihti ebameeldiv ja õnneks on see lahendatav:

public interface IEntity<TIdentity>
{
  TIdentity Id { get; }
}
public interface ISavable {}
public interface IDeletable {}
public interface IActiveRecord
  : IEntity<int>, ISavable, IDeletable {}

public static void Save(this ISavable entity)
{
  ServiceLocator.Resolve<IRepository>().Save(entity);
}

public static void Delete(this IDeletable entity)
{
  ServiceLocator.Resolve<IRepository>().Delete(entity);
}

Nende laiendusmeetodite abiga saame kenasti enda äriobjektid võõrastest raamistikest eemale hoida:

public class Person : IActiveRecord
{
  public int Id { get; set; }
  public string Name { get; set; }
}

var person = new Person();
person.Name = "Aabel";
person.Save();
person.Delete();

Kokkuvõtvalt võib öeda, et laiendusmeetodite abiga saab koodi loetavamaks muuta ning ärimudelit ja arhitektuuri parandada. Lisaks võite uurida laiendusmeetodeid Extentsion Method.NET-ist. Ja kui sul on rääkida oma lugu laiendusmeetoditest, siis ootame seda kommentaarides.

Head brokkoli söömist!

* foto: pontuse

Loe veel sarnastel teemadel:

  • Share/Bookmark

KATEGOORIAD » Arendus

SILDID » ,

3 kommentaari

1

Väga hea teema, kuna ka ise ei mäleta tavaliselt for tsükli konstruktsiooni ning ainuke abimees on siin ReSharper, kes siis teeb suure osa minu tööst ära.

Ilmselt ainuke jama extension methodite juures on see, et .Times jne hakkab hüppama külge iga int property puhul. Küll jah saab erinevaid nimeruume kasutada ja nii piirata nö esiletulemist. Pigem on tegelikult see hetke projekti ericase, sest osa arendajaid ei taha näha int-i küljes extensioneid ning seetõttu on püütud int, string jne common tüüpide puhul extensioneid piirata.

Küll aga jälgin samuti extensionmethods.net-i ning olen fän.

Mart
10:08, 7. aprill

2

R# on mindki päästnud, kuid siiski on see väga keeruliselt väljenduv konstruktsioon. Ruby-is on sellised meetodid sisse ehitatud ja annavad võimaluse ennast paremini väljendada.

Ärimudelile loodud laiendusmeetodid olen nende enaga ühte nimeruumi lisanud. Ilmselt tasub vältida hiigelsuuri laiendusmeetodite klasse.

Vahel ei ole mõttet piirata common tüüpide laiendusi, sest selle asemel kirjutatakse “helper” klassid, mis näevad veel nilbemad välja:
StringHelper.Resverse(value) või value.Reverse()

Marek Tihkan
12:27, 7. aprill

3

Pole küll ridagi C# koodi kirjutanud, aga olen sama kasutanud ohtralt JavaScriptis.

Array meetoditest on map() vaieldamatuilt populaarseim ning for-tsükkel on muutunud millegiks koodihaisu sarnaseks.

Rene Saarsoo
14:26, 7. aprill

Lisa kommentaar

  • * Kuvatakse kommentaari juures
  • * Ei publitseerita