Teie veebisait liigub edasi ja te kasvate kiiresti. Ruby / Rails on teie parim programmeerimisvõimalus. Teie meeskond on suurem ja olete juba lahkunud kontseptsioonist 'paksud mudelid, õhukesed juhid' ( paksud mudelid, kõhnad kontrollerid ) kui teie Railsi rakenduste kujundusstiil. Kuid te ei soovi ikkagi Railsi kasutamist lõpetada.
Pole probleemi. Täna arutame, kuidas kasutada OOP-i parimaid tavasid, et muuta oma kood puhtamaks, eraldatumaks ja eraldatumaks.
Alustuseks uurime, kuidas peaksite otsustama, kas teie taotlus sobib refaktoriks.
Siin on loetelu mõõdikutest ja küsimustest, mida ma tavaliselt endalt küsin, et teha kindlaks, kas minu koodid vajavad refrakteerimist või mitte.
Proovige kasutada midagi sellist, et teada saada, mitu rida Ruby lähtekoodi teil on:
find app -iname '*.rb' -type f -exec cat {} ;| wc -l
See käsk otsib kõiki rakenduse / app kaustas laiendiga .rb laiendatud faile (rubiinfailid) ja seejärel printib ridade arvu. Pange tähele, et see arv on ainult hinnanguline, kuna selle summa hulka lisatakse kommentaariread.
Teine täpsem ja informatiivsem võimalus on ülesande kasutamine reha stats
Rails, mis pakub kiiret kokkuvõtet koodiridadest, klasside arvust, meetodite arvust, meetodite suhtest klassidesse ja koodiridade suhtest meetodi kohta:
*bundle exec rake stats* +----------------------+-------+-----+-------+---------+-----+-------+ | Nombre | Líneas | LOC | Clase | Método | M/C | LOC/M | +----------------------+-------+-----+-------+---------+-----+-------+ | Controladores | 195 | 153 | 6 | 18 | 3 | 6 | | Helpers | 14 | 13 | 0 | 2 | 0 | 4 | | Modelos | 120 | 84 | 5 | 12 | 2 | 5 | | Mailers | 0 | 0 | 0 | 0 | 0 | 0 | | Javascripts | 45 | 12 | 0 | 3 | 0 | 2 | | Bibliotecas | 0 | 0 | 0 | 0 | 0 | 0 | | Controlador specs | 106 | 75 | 0 | 0 | 0 | 0 | | Helper specs | 15 | 4 | 0 | 0 | 0 | 0 | | Modelo specs | 238 | 182 | 0 | 0 | 0 | 0 | | Petición specs | 699 | 489 | 0 | 14 | 0 | 32 | | Routing specs | 35 | 26 | 0 | 0 | 0 | 0 | | Vista specs | 5 | 4 | 0 | 0 | 0 | 0 | +----------------------+-------+-----+-------+---------+-----+-------+ | Total | 1472 |1042 | 11 | 49 | 4 | 19 | +----------------------+-------+-----+-------+---------+-----+-------+ Código LOC: 262 Prueba LOC: 780 Ratio Código a Prueba: 1:3.0
Alustame reaalsest elust.
Oletame, et me tahame kirjutada rakenduse, mis jälgib sörkjooksjate ilma; Pealehel näeb kasutaja sisestatud aegu.
Igal ajakirjel on kuupäev, vahemaa, kestus ja asjakohane täiendav teave oleku kohta (nt ilm, maastiku tüüp jne) ning keskmine kiirus, mida saab vajadusel arvutada.
Vajame aruannet, mis näitab keskmist kiirust ja vahemaad nädalas. Kui keskmine kiirus sissepääsu juures on suurem kui keskmine kiirus kokku, teavitame kasutajat SMS-iga (selle näite puhul kasutame Nexmo RESTful API SMS-i saatmiseks).
Pealeht võimaldab teil valida sörkjooksu kauguse, kuupäeva ja kellaaja, et luua sarnane kirje:
mis on Kreeka kriis
Meil on ka estadísticas
leht, mis on põhimõtteliselt iganädalane aruanne, mis sisaldab nädala keskmist kiirust ja läbitud vahemaad.
aplicación
Kataloogistruktuur näeb välja selline:
⇒ tree . ├── assets │ └── ... ├── controllers │ ├── application_controller.rb │ ├── entries_controller.rb │ └── statistics_controller.rb ├── helpers │ ├── application_helper.rb │ ├── entries_helper.rb │ └── statistics_helper.rb ├── mailers ├── models │ ├── entry.rb │ └── user.rb └── views ├── devise │ └── ... ├── entries │ ├── _entry.html.erb │ ├── _form.html.erb │ └── index.html.erb ├── layouts │ └── application.html.erb └── statistics └── index.html.erb
Ma ei arutle mudeli Usuario
üle kuna see pole midagi erakordset, kuna me kasutame seda koos Moto autentimise rakendamiseks.
Mis puudutab Entrada
mudelit, sisaldab see meie rakenduse äriloogikat.
Iga Entrada
kuulub a Usuario
.
Kinnitame järgmiste atribuutide olemasolu iga sisendi jaoks distancia
, períodode_tiempo
, fecha_hora
ja estatus
.
Iga kord, kui loome kirje, võrdleme kasutaja keskmist kiirust kõigi süsteemi kasutajate keskmisega ja teavitame kasutajat SMS-iga, kasutades Nexmo (Me ei aruta, kuidas Nexmo teeki kasutatakse, kuigi tahtsin näidata juhtumit, kus kasutame välist teeki).
Pange tähele, et Entrada
mudel sisaldab enamat kui ainult äriloogikat. Samuti tegeleb see mõne kinnitamise ja kõnega.
entries_controller.rb
omab aktsiaid JUUR peamine (ehkki värskenduseta). EntriesController#index
saab praeguse kasutaja kirjed ja sorteerib kirjed loomise kuupäeva järgi, samal ajal kui EntriesController#create
looge uus kirje. Ei ole vaja arutada EntriesController#destroy
ilmset ega vastutust :
Kuigi statistics_controller.rb
vastutab nädalaaruande arvutamise eest StatisticsController#index
saab sisselogitud kasutaja kirjed ja rühmitab need nädala kaupa, kasutades #group_by
mis on klassis Loendamatu rööbastes. Seejärel proovige tulemusi privaatsete meetodite abil kaunistada.
Me ei aruta siin vaateid palju, kuna lähtekood on iseenesestmõistetav.
Allpool on vaade sisseloginud kasutaja (index.html.erb
) kirjete loetlemiseks. Seda mustrit kasutatakse indeksi toimingu (meetodi) tulemuste kuvamiseks sisendkäitluses:
Pange tähele, et kasutame render @entries
Partialid, et viia jagatud kood osaliseks mustriks _entry.html.erb
et saaksime oma koodi säilitada KUIV ja korduvkasutatavad:
Sama kehtib ka _forma
osaline. Selle asemel, et kasutada sama koodi (uute ja muudetud) toimingutega, loome korduvkasutatava osalise vormi:
Nädalase aruande lehe vaate osas statistics/index.html.erb
näitab statistikat ja aruandeid kasutaja iganädalaste tegevuste kohta, rühmitades mõned kirjed:
Ja lõpuks, abistaja sisendite puhul sisaldab entries_helper.rb
abistajad readable_time_period
ja readable_speed
mis peaks atribuute hõlpsamini lugema:
node.js ekspress rest api näide
Siiani pole midagi liiga keerulist.
Enamik teist võib väita, et selle ümbertegemine on põhimõttega vastuolus KISS ja see muudab süsteemi keerukamaks.
Kas see rakendus tuleb siis tõesti ümber teha?
Absoluutselt ei , kuid kaalume seda ainult valimi eesmärgil.
Lõppude lõpuks, kui vaatate järgmist jaotist ja omadusi, mis näitavad, et rakendus vajab taastamist, saab ilmseks, et meie näites toodud rakendus ei ole sobiv refaktoreerimise kandidaat.
Alustame struktuurimustri selgitamisest MVC rööbastes.
Tavaliselt algab see otsingumootorist, tehes sellise päringu nagu https://www.toptal.com/jogging/show/1
.
Veebiserver võtab päringu vastu ja kasutab rutas
määratleda, mida controlador
kasutamine.
Kontrollerid analüüsivad kasutaja päringuid, andmeedastust, küpsiseid, seansse jne ja analüüsivad seejärel modelo
saada andmeid.
modelos
Need on rubiiniklassid, mis räägivad andmebaasiga, salvestavad ja kinnitavad andmeid, täidavad äriloogikat ja teevad rasket tõsta. Vaated on need, mida kasutaja näeb: HTML, CSS, XML, Javascript, JSON.
Kui tahame näidata Railsi elutsüklitaotluse järjestust, näeks see välja järgmine:
Mida ma tahan saavutada, on lisada rohkem abstraktsioone, kasutades PORO-sid, ja muuta muster toimingutega create/update
järgmiseks:
Ja midagi sarnast toimingute jaoks list/show
:
POROs sisalduvate abstraktsioonide lisamisega tagame vastutuse täieliku lahususe HAIGE , midagi, mida Rails täielikult ei valda.
Uue kujunduse saavutamiseks kasutan allolevaid juhiseid, kuid pidage meeles, et need pole reeglid, mida peate tähele järgima. Mõelge neile kui paindlikele juhistele, mis muudavad taastamise lihtsamaks.
ActiveRecordi mudelid võivad sisaldada seoseid ja konstante, kuid mitte midagi muud. See tähendab, et ei toimu kõnesid (kasutage teenuse objekte ja lisage sinna kõned) ega valideerimisi (kasutamine Vormi objektid lisada mudeli nimed ja valideerimised).
Hoidke kontrollereid õhukeste kihtidena ja helistage alati teenuse objektidele. Mõni teist võib küsida, miks peaks kontrollereid kasutama, kui tahame loogikat sisaldavaid teenuseobjekte pidevalt kutsuda? Kontrollerid on hea koht marsruutimine HTTP, parameetrite parsimine, autentimine, sisuline läbirääkimine, õige teenuse või redaktori objekti kutsumine, erandite püüdmine, vastuste vormindamine ja õige HTTP-koodi oleku tagastamine.
Päringud tuleks teha esemetega päring . Objekti meetodid Päring peab tagastama objekti, a räsi või massiiv , kuid mitte ActiveRecordi seost.
Vältige kasutamist Abistajad , paremini kasutada dekoraatoreid. Miks? Ühine raskus abistajad Railsis on see, et neid saab muuta hunnikuks mitte- OO , mis jagavad ruuminime ja kattuvad üksteisega. Kuid see on palju hullem, et mitte see, et te ei saa polümorfismi kasutada abistajad Rööpad - pakkudes erinevat rakendust erinevatele kontekstidele või tüüpidele ning möödaminnes või alamklassifitseerides abilisi. Ma arvan, et sellised abistaja rööbastes tuleks neid tavaliselt kasutada kasulike meetodite jaoks, mitte konkreetsete kasutusviiside jaoks; kuidas vormindada mis tahes esitlusloogika mudeli atribuute. Hoidke need kerged ja hõlpsasti jälgitavad. Kaunistajad / delegaadid paremad. ** Miks? Lõppude lõpuks näivad mured olevat Railsi osa ja need võivad kuivada ( KUIV ) kood, kui seda jagatakse mitme mudeli vahel. Suurem probleem on aga see, et mured ei muuda mudeli objekti sidusamaks. Ainult kood on paremini korraldatud. Teisisõnu, mudeli API-l pole tegelikke muudatusi.
Proovige välja tõmmata Väärtuslikud esemed mudelitest hoida oma kood puhtamana ja grupiga seotud atribuudid.
Enne alustamist tahan midagi muud arutada. Kui refaktoreerimine algab, mõtlete tavaliselt: 'Kas see on hea refrakteerimine?'
Kui tunnete, et eraldate või eraldate rohkem kohustusi (isegi kui see tähendab rohkem koodi ja uute failide lisamist), on see hea. Lõppude lõpuks on rakenduse eraldamine väga hea tava ja see lihtsustab meil korraliku ühikutesti tegemist.
Ma ei hakka arutama asju, nagu näiteks loogika liikumine kontrolleritelt mudelitele, kuna eeldan, et teete seda ja teil on Railsi (tavaliselt Skinny Controller ja FAT mudel) mugav.
Selle artikli kokkuvõtlikkuse huvides ei hakka ma arutama, kuidas testida, kuid see ei tähenda, et te ei peaks testima.
Vastupidi, peaksite alusta alati testiga enne edasiliikumist veendumaks, et asjad sujuvad. See on midagi nõutud, eriti refrakteerimisel.
Seejärel saame muudatusi rakendada ja veenduda, et testid läbiksid koodi asjakohased osad.
Esiteks, mis on väärtuslik objekt?
Martin Fowler Seletama:
Väärtusobjekt on väike objekt, näiteks raha- või kuupäevavahemiku objekt. Nende peamine omadus on see, et nad järgivad väärtussemantikat, mitte referentssemantikat.
Mõnikord võite sattuda olukorda, kus mõiste väärib oma abstraktsiooni ja kus selle võrdsus ei põhine väärtustel, vaid identiteedil. Selle näiteks võib olla: Ruby's Date, URI ja Pathname. Väärtusliku objekti (või domeenimudeli) väljavõtmine on suur mugavus.
Miks vaeva näha?
Väärtusobjekti üks suur eelis on see, et need aitavad teie koodis ilmekust saavutada. Teie kood kipub olema selgem või vähemalt nii võib see olla, kui teil on head nimetamistavad. Kuna väärtusobjekt on abstraktsioon, toob see kaasa selgemad koodid ja vähem vigu.
Teine kasu on muutumatus . Esemete muutumatus on väga oluline. Kui me salvestame teatud andmekogumeid, mida saab väärtusobjektis kasutada, ei meeldi mulle tavaliselt andmetega manipuleerimine.
Millal see kasulik on?
Sellele küsimusele pole täiuslikku vastust. Tehke seda, mis on teile parim ja mis on antud olukorras kõige mõistlikum.
Lisaks sellele on mõned juhised, mida kasutan selle otsuse tegemisel.
Kui arvate, et rühm meetodeid on omavahel seotud, on väärisesemed kallimad. See väljendusrikkus tähendab, et väärtusobjekt peaks tähistama eristavat andmekogumit, mille teie keskmine arendaja saab tuletada lihtsalt objekti nime vaadates.
veebisaidid, mis kasutavad gestalt põhimõtteid
Kuidas seda teha?
Väärisesemed peaksid järgima teatavaid reegleid:
Meie näites loome atribuutide EntryStatus
abstraktseks väärtusobjekti Entry#status_weather
ja Entry#status_landform
oma klassi, mis näeb välja selline:
Märkus. See on lihtsalt PORO (tavaline vana rubiinobjekt), seda ei pärita ActiveRecord::Base
Oleme oma atribuutide jaoks määranud lugeja meetodid ja määrame need käivitamisel. Samuti kasutame objektide sobitamiseks meetodi () abil võrreldavat segu.
Saame mudelit muuta Entry
meie loodud väärtusobjekti kasutamiseks:
Samuti saame modifitseerida meetodit EntryController#create
uue väärtuse objekti vastavalt kasutamiseks:
Mis on teenuse objekt?
Teenuse objekti ülesandeks on koodi hoidmine äriloogika kindlas ruumis. Erinevalt stiilist 'Paks mudel' , kus väike arv objekte sisaldab kogu vajaliku loogika jaoks palju-palju meetodeid, tulemuseks on teenuseobjektide kasutamine paljudes klassides, millest kõigil on ainulaadne eesmärk.
Miks? Mis on selle eelised?
Lahku tõmbama. Teenuseobjektid aitavad teil objektide vahel rohkem isoleerida.
Nähtavus. Teenuse objektid (kui neil on õige nimi) näitavad, mida rakendus teeb. Võin teenuste kataloogist läbi vaadata, et näha, milliseid võimalusi rakendus pakub.
KUIV ja nõustu muudatusega. Teenuse esemed hoian võimalikult lihtsad ja väikesed. Koostan teenuseobjektid teiste teenuseobjektidega ja kasutan neid uuesti.
Puhastage ja kiirendage oma testipaketti. Teenuseid on kiire ja lihtne testida, kuna need on väikesed rubiinobjektid, millel on sisenemispunkt (nn meetod). Komplekssed teenused on ühendatud teiste teenustega, nii et saate testid hõlpsasti eraldada. Samuti hõlbustab teenuseobjektide kasutamine seotud objektide hankimist kogu rööbaste keskkonda laadimata.
Teiselt poolt pole miski täiuslik. Teenuseobjektide üks puudus on see, et need võivad iga väikese toimingu puhul olla üle jõu. Sellistel juhtudel võite lõpuks oma koodi keerulisemaks muuta ja mitte lihtsustada.
Millal peaksite teenuse objekte välja pakkima?
Ka siin pole kindlat reeglit.
Tavaliselt on teenuseobjektid parimad keskmistele ja suurtele süsteemidele: korraliku loogikaga süsteemidele, tavalistest CRUD-toimingutest kaugemale.
Nii et kui arvate, et koodijupp ei kuulu kataloogi, on kohas, kuhu kavatsesite selle lisada, tasub see uuesti läbi mõelda ja vaadata, kas oleks parem, kui see läheks teenuseobjektile.
Siin on mõned näpunäited teenuse objektide kasutamise kohta:
raspberry pi veebiserver nginx
Kuidas peaksite teenuseobjekte kujundama?
Teenuseobjekti klassi kujundamine on suhteliselt lihtne, kuna te ei vaja seda kalliskivid te ei peaks õppima a DLS uus, kuid kui suudate enam-vähem toetuda juba olemasolevatele tarkvara kujundamise oskustele.
Tavaliselt kasutan teenuse objekti kujundamiseks järgmisi juhiseid ja tavasid:
app/services
alla . Soovitan teil tugevate äriloogika domeenide jaoks kasutada alamkatalooge. Näiteks fail app/services/report/generate_weekly.rb
määratleb Report::GenerateWeekly
samal ajal app/services/report/publish_monthly.rb
määratleb Report::PublishMonthly
ApproveTransaction
, SendTestNewsletter
, ImportUsersFromCsv
.Kui vaatate StatisticsController#index
, siis märkate kontrollerile rühmitatud meetodite rühma (weeks_to_date_from
, weeks_to_date_to
, avg_distance
jne). See ei ole hea. Mõelge tagajärgedele, kui soovite nädala aruande luua väljaspool statistics_controller
Meie puhul loome Report::GenerateWeekly
ja väljavõtke loogikaaruanne StatisticsController
Niisiis StatisticsController#index
nüüd näeb see puhtam välja:
Rakendades teenuse objekti mustrit, rühmitame koodi keeruka ja konkreetse toimingu ümber ning edendame väiksemate ja selgemate meetodite loomist.
Kodutöö: kaaluge kasutamist Väärtuslik objekt WeeklyReport
jaoks Struct
asemel .
Mis on objekt Päring ?
Objekt Päring on PORE, mis tähistab päringute andmebaasi. Seda saab taaskasutada rakenduse erinevates kohtades, varjates samal ajal päringuloogikat. Samuti on see testimiseks hea isoleeritud seade.
Peaksite keerukad SQL / NoSQL-päringud eraldama oma klassidesse.
Iga objekt Päring vastutab tulemuste kogumi tagastamise eest, lähtudes kriteeriumidest / ärireeglitest.
Selles näites pole meil päringut ( päring ) keeruline, nii et kasutage objekti Päring see ei oleks tõhus. Kuid demonstreerimise eesmärgil eraldame päringu Report::GenerateWeekly#call
ja loome generate_entries_query.rb
:
Ja asendame Report::GenerateWeekly#call
def call @user.entries.group_by(&:week).map do |week, entries| WeeklyReport.new( ... ) end end
koos:
def call weekly_grouped_entries = GroupEntriesQuery.new(@user).call weekly_grouped_entries.map do |week, entries| WeeklyReport.new( ... ) end end
Objekti muster päring (päring) aitab hoida teie mudeli loogikat rangelt seotud klassi käitumisega, hoides samal ajal oma kontrollereid kõhnana. Sest nad pole muud kui tavalised vanad Ruby klassid , objektid päring nad ei pea pärima ActiveRecord::Base
-st ja peaksid vastutama muu kui päringu täitmise eest.
Nüüd võtame välja uue teenuseobjekti uue kirje loomise loogika. Kasutame konventsiooni ja loome CreateEntry
:
Ja nüüd on meie EntriesController#create
on järgmine:
def create begin CreateEntry.new(current_user, entry_params).call flash[:notice] = 'Entry was successfully created.' rescue Exception => e flash[:error] = e.message end redirect_to root_path end
Nüüd hakkavad asjad huvitavamaks minema.
Pidage meeles, et meie juhistes leppisime kokku, et soovime, et mudelitel oleksid assotsiatsioonid ja konstandid, kuid mitte midagi muud (ei valideerimisi ega kõnesid). Alustame tähelepanulaiendite eemaldamisega ja kasutame selle asemel objekti Shape.
Kujuobjekt on PORO (tavaline vana rubiinobjekt). Kui peate andmebaasiga rääkima, võtke kontroller / teenuseobjekt käsku.
Miks kasutada Shape objekte?
Kui peate oma rakenduse ümber kujundama, on alati hea meeles pidada peamist vastutust ( HAIGE ).
HAIGE aitab teil teha paremaid kujundusotsuseid klassiga seotud vastutuse osas.
Näiteks teie andmebaasitabeli mudel (rööbaste kontekstis ActiveRecordi mudel) tähistab koodis ainulaadset andmebaasikirjet, nii et teil pole põhjust muretseda midagi, mida teie kasutaja teeb.
Siit tuleb Shape objekt.
Kujuobjekt vastutab teie rakenduses kuju esindamise eest. Seega saab iga sisendvälja käsitleda tunnis atribuudina. Võite kinnitada, et need atribuudid vastavad mõnele valideerimisreeglile, ja võite edastada 'puhtad' andmed sinna, kuhu need peaksid minema (nt teie andmebaasi mudel või võib-olla teie päringuotsingu koostaja).
Millal peaksite kasutama objekti Shape?
See võimaldab teil kogu oma vormiloogika (nimetamiskonventsioonid, valideerimised ja muud) ühte kohta panna.
Kuidas luua objekti Shape?
ActiveModel::Model
(Rööbastesse 3 peate selle asemel lisama nime, teisenduse ja valideerimise).Pange tähele, et saate kasutada pärl reform , kuid jätkates PORO-ga, loome entry_form.rb
mis näeb välja selline:
Ja me muudame CreateEntry
objekti Vorming EntryForm
kasutamise alustamiseks:
class CreateEntry ...... ...... def call @entry_form = ::EntryForm.new(@params) if @entry_form.valid? .... else .... end end end
Märge: Mõni teist ütleb, et teenuse objektilt pole vaja Shape-objekti juurde pääseda ja me võime Shape-objektile helistada otse kontrollerilt, mis on kehtiv argument. Kuid mul oleks pigem selge voog, seetõttu helistan alati vormi objekt teenuse objektilt.
Nagu me varem kokku leppisime, ei soovi me, et meie mudelid sisaldaksid valideerimisi ja kõnesid. Tõmbasime valideerimised objektide Shape abil. Kuid me kasutame endiselt mõnda kõnet (after_create
mudelis Entry
compare_speed_and_notify_user
).
Miks me tahame modellidest kõned eemaldada?
Rööbaste arendajad testide ajal hakkavad nad tavaliselt helistamise ajal valu tundma. Kui te ei testi oma ActiveRecordi mudeleid, hakkate valusid märkama hiljem, kui teie rakendus kasvab ja kuna helistamiseks või kõnede vältimiseks on vaja rohkem loogikat.
después_*
kõnesid kasutatakse peamiselt seoses objekti salvestamise või sellega jätkamisega.
Kui objekt on salvestatud, on objekti eesmärk (nt vastutus) täidetud. Nii et kui me ikkagi näeme, et kõnesid kutsutakse, siis pärast objekti salvestamist on need tõenäoliselt kõned, mille eesmärk on pääseda objekti vastutusalast välja ja siis tekivad meil probleemid.
Meie puhul saadame kasutajale SMS-i, mis pole seotud sisenddomeeniga.
toote hinnaelastsuse teadmine võimaldab majandusteadlastel:
Lihtne viis probleemi lahendamiseks on kõne viimine seotud teenuse objektile. Lõppude lõpuks on SMS-i saatmine vastavale kasutajale seotud teenuseobjektiga CreateEntry
mitte sisenemismudel kui selline.
Seda tehes ei pea me enam sulgema, compare_speed_and_notify_user
meie testides. Oleme teinud selle lihtsaks, luues sissekande ilma SMS-i saatmata ja järgime head objektile orienteeritud kujundust, tagades, et meie klassidel on ainulaadne vastutus ( HAIGE ).
Nii et nüüd CreateEntry
see on midagi sarnast sellega:
Kuigi saame kollektsiooni hõlpsalt kasutada Draper vaatemudelite ja sisekujundajate osas jään PORO juurde, selle artikli jaoks, nagu olen siiani teinud.
Mul on vaja klassi, mis kutsub kaunistatud objektil meetodeid.
Ma saan kasutada method_missing
selle rakendamiseks, kuid ma kasutan standardset Ruby teeki SimpleDelegator
. Järgmine kood näitab, kuidas SimpleDelegator
meie baasdekoraatori rakendamiseks:
% app/decorators/base_decorator.rb require 'delegate' class BaseDecorator Miks meetod _h
See meetod toimib vaate konteksti puhverserverina. Vaikimisi on vaate kontekst vaate klassi eksemplar, selleks on ActionView::Base
Teil on juurdepääs abistajad seisukohti järgmiselt:
_h.content_tag :div, 'my-div', class: 'my-class'
Selle mugavamaks muutmiseks lisame meetodi decorado
a ApplicationHelper
:
module ApplicationHelper # ..... def decorate(object, klass = nil) klass ||= '#{object.class}Decorator'.constantize decorator = klass.new(object, self) yield decorator if block_given? decorator end # ..... end
Nüüd saame liikuda abistajad EntriesHelper
dekoraatoritele:
# app/decorators/entry_decorator.rb class EntryDecorator Ja saame kasutada readable_time_period
ja readable_speed
järgnevalt:
# app/views/entries/_entry.html.erb - +
- +
Struktuur pärast taastamist
Lõpuks saime rohkem faile, kuid see pole tingimata halb asi (ja pidage meeles, et algusest peale olime teadlikud, et see näide oli mõeldud tutvustamiseks ja ei oli tingimata hea taaskasutamise juhtum):
app ├── assets │ └── ... ├── controllers │ ├── application_controller.rb │ ├── entries_controller.rb │ └── statistics_controller.rb ├── decorators │ ├── base_decorator.rb │ └── entry_decorator.rb ├── forms │ └── entry_form.rb ├── helpers │ └── application_helper.rb ├── mailers ├── models │ ├── entry.rb │ ├── entry_status.rb │ └── user.rb ├── queries │ └── group_entries_query.rb ├── services │ ├── create_entry.rb │ └── report │ └── generate_weekly.rb └── views ├── devise │ └── .. ├── entries │ ├── _entry.html.erb │ ├── _form.html.erb │ └── index.html.erb ├── layouts │ └── application.html.erb └── statistics └── index.html.erb
järeldus
Kuigi selles blogipostituses keskendume Railsile, ei sõltu RoR (Ruby on Rails) teenuseobjektidest ega muudest PORO-dest. Seda lähenemist saate kasutada ükskõik millisega raamistiku veeb , mobiili- või konsoolirakendus.
Kasutamisel MVC Arhitektuurina kleepub kõik kokku ja aeglustab teid, sest enamik muudatusi mõjutab rakenduse muid osi. Samuti sunnib teid mõtlema, kuhu panna mõni äriloogika - kas see peaks minema mudeli, kontrolleri või vaate sisse?
Lihtsa PORO abil oleme viinud äriloogika mudelitesse või teenustesse, mis ei pärine ActiveRecord
-st, mis on juba kasum, rääkimata sellest, et meil on selgem kood, mis toetab HAIGE ja kiirem seadmete testimine.
Puhas arhitektuur üritab panna kasutuskastid oma struktuuri keskele / ülaossa, nii et näeksite hõlpsalt, mida teie rakendus teeb. See hõlbustab ka muudatuste vastuvõtmist, kuna see on modulaarsem ja isoleeritum. Loodan, et olen näidanud, kuidas Tavalised vanad rubiinobjektid ja rohkem abstraktsioone, see eraldab mured, lihtsustab testimist ja aitab luua puhast ja hooldatavat koodi.
Seotud: Mis kasu on Ruby on Rails'ist? Pärast kaks aastakümmet programmeerimist. Kasutage rööpaid