Dünaamiliste keelte maailmas tuntud termin monkeypatching tähendab meetodite lisamist/muutmist rakenduse töötamise ajal. See on küllaltki võimas vahend koodi kirjutamisel, kuid seal on ka suured ohud kui vääralt seda kasutada.
Näiteks muutes raamistiku poolt väljapakutud käitumist lihtsameelselt võib külvata kõvasti segadust. Samas raamistiku klasse funktsionaalsuse osas laiendada pole halb mõte. Seda on on võimalik ka teha C# 3.0 laiendusmeetoditega. Kuigi dünaamilistes keeltes ei ole lahendatud see illusoorselt.
Laiendusmeetodid
Laiendusmeetodite peamine idee C# võiks olla staatiliste util klasside eemaldamine. See küll ei eemalda neid tegelikult, vaid on rohkem illusiooniks koodi kirjutamisel.
public static class StringExtensions
{
public static string Reverse(this string value)
{
...
}
}
Seda nüüd kasutada oleks ilus ja kena:
string name = "Stepiahv"; string reversedName = name.Reverse();
Tegelikult kompileeritult võib näha kenasti, kuidas kutsutakse
string reservedName = StringExtensions.Reverse(name);
Selliseid util klasside laiendusmeetodeid leiab hulgaliselt ka internetist. See kõik on tore, kuid arvan, et kasu annab veidi rohkem neist lõigata. Head näited paremast kasutamisest võib leida NUnit Extension methods projektist, kus pidevalt Assert.That() vms meetodi asemel on poogitud objektidele külge Should() meetod.
var actual = new object(); Assert.That(actual, Is.Not.Null); actual.Should(Be.Not.Null);
Kui vaadata projekti koodi, siis pole seal oluliselt seda ollagi. Klass Be pärib kõik meetodid NUniti klassilt Is ja Have Has-ilt. Samas loetavus võib olla parem.
Teine koht, kus leiab head laiendusmeetodite kasutust on Rhino Mocks. Kuna võltsitud objektid pärivad tõelise objekti liideselt, siis on siinkohalgi hea kasutada illusiooni loetavuse jaoks:
var person = MockRepository.GenerateMock<iperson>();
person.Expect(x => x.Alias).Return("Stepiahv");
...
person.VerifyAllExpectations();
Kui vaadata neid mõlemaid, siis võiks öelda, et ka siin juhul asendatakse util tüüpi klass välja. Siiski tunduvad need midagi rohkemat olevat, ilmselt sellest, et need teevad selle DSL-ilikumaks.
Eelmises postituses oli kasutatud laiendusmeetodeid üsna julgelt:
public static void ActionExtensions
{
public static void When(this Action action, bool expression)
{
if (expression)
action.Invoke();
}
public static void Unless(this Action action, bool expression)
{
if (!expression)
action.Invoke();
}
public static void Now(this Action action)
{
action.Invoke();
}
}
public static IntExtensions
{
public static void Times(this int times, Action action)
{
for (int i = 0; i < Math.Abs(times); i++)
{
action.Invoke();
}
}
}
Need on mõned laiendusmeetodid, mis tegid selle koodi selliseks nagu ta seal oli.
Proovisin ka veel ühte huvitavat lähenemist, mida võib Ninjectist leida. See küll on veidi edasiarendus, mida sealses koodis näha võis: kui teha objekt klassile näiteks laiendusmeetodi Do(this object value, Action action), siis suvalise klassi meetodi sees võiks saada seda kasutada järgmiselt:
Do(() => ...)
kuid kahjuks seda ei lubata. Peab kirjutama selle
this.Do(() => ...)
Selle eesmärk oleks olla Action klassi nö factory. Muidu tuleks eelnevaid meetodeid väga kohmakalt kasutada:
new Action(() => ...).Unless(5 % 2 == 0)
See lihtsalt pole väga kena. Ninjectis kasutati taolist võttet:
class ConfigurationModule : StandardModule
{
public void Load()
{
Bind<iperson>().To<person>();
}
}
Seal on näha, et meetod Bind on StandardModule meetod ja Load meetodis saab seda kenasti kasutada. Igati ilus lähenemine.
Laiendusmeetodeid annab käsitleda ka veel liideste teisendamist abstraktseteks klassideks. See küll ei tee seda otseselt, kuid luues näiteks ICompareble liidesele juurde meetodid GreaterThan, LessThan jne laiendusmeetoditena, siis nende kooslus oleks justkui abstraktne klass.
Igal juhul loodan, et saite vähemalt mõningaid mõtteid, kuidas laiendusmeetodeid kasutada võiks ja kui vähegi tahtmist on arutada neid, siis andke neist kommentaarides teada.
Loe veel sarnastel teemadel:
- Ebameeldivad erijuhud, 21. jaanuar
- Rubylik C#: Why’s (Poignant) Guide to Ruby, 23. oktoober
- Programmeerimine ilma tsükliteta, 16. aprill
- Vaesed inimesed, 28. jaanuar
- Iluvõtted koodile I, 7. aprill
KAIZEN FEED
Telli endale Kaizeni uudisvoog
KOMMENTAARIDE FEED
Telli endale kommentaaride voog
KAIZEN TWITTER
Lühiuudised Kaizeni autoritelt
KAIZEN FACEBOOK
Liitu Kaizeniga
MIS ON KAIZEN?
Kaizen on Saiku tarkvaraarendusealane blogi, kus kirjutame erinevatest lähenemistest meisterlikule tarkvaraarendusele.
KATEGOORIAD
- .NET (18)
- Analüüs/Arhitektuur (11)
- Arendus (66)
- Ettevalmistus (1)
- Juhtimine (2)
- Varia (23)
SILDIPILV
- .NET (41)
- ilus kood (23)
- Arendus (23)
- C# (20)
- Analüüs/Arhitektuur (14)
- Testimine (10)
- raamat (8)
- Ruby (8)
- projektijuhtimine (8)
- printsiibid (6)
- produktiivsus (5)
- ReSharper (5)
- PHP (5)
- NHibernate (4)
- objekt-orienteeritud (4)
- pidev integratsioon (4)
- Viited (4)
- agile (4)
- Java (4)
- Geekdinner (4)
- lean (4)
- raamatukogu (4)
- CI (3)
- Cruise Control.NET (3)
- Robert C. Martin (3)
- scrum (3)
- iteratsioon (3)
- suhtlus (3)
- jQuery (2)
- TechEd 2008 (2)
- Visual Studio (2)
- valideerimine (2)
- intervjuu (2)
- analüüs (1)
- ASP.NET (1)
- ümberstruktureerimine (1)
- üritus (1)
- CodeRush (1)
- dokumentatsioon (1)
- Kent Beck (1)
- LINQ (1)
- Martin Fowler (1)
- Moq (1)
- Rhino Mocks (1)
- stackoverflow (1)
- võltsitud objektid (1)
- Whiteboard Wednesday (1)
- hindamine (1)
- tarkvara kvaliteet (1)
- ajagraafikud (1)
- Saiku (1)
- koolitus (1)
- tagasivaate (1)
- koosolek (1)
- dünaamilised keeled (1)
- staatilised keeled (1)
- FluentNHibernate (1)
- facebook (1)
- aastapäev (1)
- Rake (1)
- Oredev 2008 (1)
- toyota way (1)
- raiskamine (1)
- NDepend (1)
- podcasts (1)
- väle tarkvaraarendus (1)
- raido tonts (1)
- minimal marketable feature (1)
- kasutajalugu (1)
- twitter (1)
- Joomla! (1)
- MVC (1)
- andmebaas (1)
- versioonimine (1)
- diskussioon (1)
- regulaaravaldised (1)
- motiveerimine (1)
- mõõdikud (1)
- agileestonia (1)
- riistvara (1)
- koolitused (1)
- kujundus (1)
- kodulehed (1)
- veeb (1)
