"Kumusta Kaibigan!"

"Hi, Bilaabo!"

"Mayroon pa tayong ilang oras, kaya sasabihin ko sa iyo ang tungkol sa tatlong higit pang mga pattern."

"Tatlo pa? Ilan lahat?"

"Sa kasalukuyan ay may dose-dosenang mga sikat na pattern, ngunit ang bilang ng mga «matagumpay na solusyon» ay walang limitasyon."

"I see. Kaya kailangan kong matuto ng ilang dosenang pattern?"

"Hanggang sa mayroon kang tunay na karanasan sa programming, hindi ka nila bibigyan ng marami."

"Mas mabuting makakuha ka ng kaunti pang karanasan, at pagkatapos, sa isang taon, bumalik sa paksang ito at subukang unawain ang mga ito nang mas malalim. Hindi bababa sa ilang dosenang mga pinakasikat na pattern ng disenyo."

"Isang kasalanan na huwag gumamit ng karanasan ng ibang tao at sa halip ay mag-imbento ng isang bagay sa ika-110 na pagkakataon."

"Sumasang-ayon ako."

"Kung ganoon ay magsimula na tayo."

Pattern ng adaptor (o wrapper).

Mga Pattern: Adapter, Proxy, Bridge - 1

"Isipin na pumunta ka sa China at nalaman na ang mga saksakan ng kuryente ay sumusunod sa ibang pamantayan. Ang mga butas ay hindi bilog, ngunit patag. Sa kasong ito, kakailanganin mo ng adaptor."

"Ang isang bagay na katulad ay maaari ding mangyari sa programming. Ang mga klase ay nagpapatakbo sa magkatulad ngunit magkaibang mga interface. Kaya kailangan nating gumawa ng adaptor sa pagitan nila."

"Ganito ang hitsura nito:"

Halimbawa
interface Time
{
 int getSeconds();
 int getMinutes();
 int getHours();
}

interface TotalTime
{
 int getTotalSeconds();
}

"Ipagpalagay na mayroon kaming dalawang interface: Oras  at  TotalTime ."

"Ang Time interface ay nagbibigay-daan sa iyong makuha ang kasalukuyang oras gamit ang getSeconds (),  getMinutes () at  getHours () na mga pamamaraan."

"Ang TotalTime interface ay nagbibigay-daan sa iyong makuha ang bilang ng mga segundo na lumipas mula hatinggabi hanggang sa kasalukuyang sandali."

"Ano ang dapat nating gawin kung mayroon tayong TotalTime object, ngunit kailangan natin ng Time object o vice versa?"

"Maaari kaming sumulat ng mga klase ng adaptor para dito. Halimbawa:"

Halimbawa
 class TotalTimeAdapter implements Time
{
 private TotalTime totalTime;
 public TotalTimeAdapter(TotalTime totalTime)
 {
  this.totalTime = totalTime;
 }

 int getSeconds()
 {
  return totalTime.getTotalSeconds() % 60; // seconds
 }

 int getMinutes()
 {
  return totalTime.getTotalSeconds() / 60; // minutes
 }

 int getHours()
 {
  return totalTime.getTotalSeconds() / (60 * 60); // hours
 }
}
 
Paggamit
TotalTime totalTime = TimeManager.getCurrentTime();
Time time = new TotalTimeAdapter(totalTime);
System.out.println(time.getHours() + " : " + time.getMinutes () + " : " +time.getSeconds());

"At isang adaptor sa kabilang direksyon:"

Halimbawa
class TimeAdapter implements TotalTime
{
 private Time time;
 public TimeAdapter(Time time)
 {
  this.time = time;
 }

 int getTotalSeconds()
 {
  return time.getHours() * 60 * 60 + time.getMinutes() * 60 + time.getSeconds();
 }
}
Paggamit
Time time = new Time();
TotalTime totalTime = new TimeAdapter(time);
System.out.println(time.getTotalSeconds());

"Ah. Gusto ko. Pero may mga halimbawa ba?"

"Siyempre! Bilang halimbawa, ang InputStreamReader ay isang klasikong adaptor. Kino-convert nito ang isang InputStream sa isang Reader."

"Minsan ang pattern na ito ay tinatawag ding wrapper, dahil ang bagong klase ay 'nagbabalot' ng isa pang bagay."

"Maaari kang magbasa ng ilang iba pang mga kawili-wiling bagay dito ."

Pattern ng proxy

"Ang proxy pattern ay medyo katulad sa pattern ng wrapper. Ngunit ang layunin nito ay hindi upang i-convert ang mga interface, ngunit upang kontrolin ang access sa orihinal na bagay na nakaimbak sa loob ng proxy class. Bukod dito, ang parehong orihinal na klase at ang proxy ay karaniwang may parehong interface, na ginagawang mas madaling palitan ang isang object ng orihinal na klase ng isang proxy object."

"Halimbawa:"

Interface ng totoong klase
interface Bank
{
 public void setUserMoney(User user, double money);
 public int getUserMoney(User user);
}
Pagpapatupad ng orihinal na klase
class CitiBank implements Bank
{
 public void setUserMoney(User user, double money)
 {
  UserDAO.updateMoney(user, money);
 }

 public int getUserMoney(User user)
 {
  return UserDAO.getMoney(user);
 }
}
Pagpapatupad ng klase ng proxy
class BankSecurityProxy implements Bank
{
 private Bank bank;
 public BankSecurityProxy(Bank bank)
 {
  this.bank = bank;
 }
 public void setUserMoney(User user, double money)
 {
  if (!SecurityManager.authorize(user, BankAccounts.Manager))
  throw new SecurityException("User can’t change money value");

  bank.setUserMoney(user, money);
 }

 public int getUserMoney(User user)
 {
  if (!SecurityManager.authorize(user, BankAccounts.Manager))
  throw new SecurityException("User can’t get money value");

  return bank.getUserMoney(user);
 }
}

"Sa halimbawa sa itaas, inilarawan namin ang interface ng Bank at ang klase ng CitiBank , isang pagpapatupad ng interface na ito."

"Hinahayaan ka ng interface na makuha o baguhin ang balanse ng account ng isang user."

At pagkatapos ay nilikha namin ang BankSecurityProxy , na nagpapatupad din ng interface ng Bank at nag-iimbak ng reference sa ibang interface ng Bank. Ang mga pamamaraan ng klase na ito ay nagsusuri kung ang user ay ang may-ari ng account o isang bank manager. Kung hindi, may itatapon na SecurityException."

"Narito kung paano ito gumagana sa pagsasanay:"

Code na walang mga pagsusuri sa seguridad:
User user = AuthManager.authorize(login, password);
Bank bank = BankFactory.createUserBank(user);
bank.setUserMoney(user, 1000000);
Code na may mga pagsusuri sa seguridad:
User user = AuthManager.authorize(login, password);
Bank bank = BankFactory.createUserBank(user);
bank = new BankSecurityProxy(bank);
bank.setUserMoney(user, 1000000);

"Sa unang halimbawa, lumikha kami ng isang bagay sa bangko at tinatawag ang pamamaraang setUserMoney nito .

"Sa pangalawang halimbawa, binabalot namin ang orihinal na bagay sa bangko sa isang bagay na BankSecurityProxy . Ang mga ito ay may parehong interface, kaya ang kasunod na code ay patuloy na gagana tulad ng ginawa nito. Ngunit ngayon ang isang pagsusuri sa seguridad ay isasagawa sa tuwing tatawagin ang isang paraan."

"Malamig!"

"Oo. Maaari kang magkaroon ng maraming ganoong proxy. Halimbawa, maaari kang magdagdag ng isa pang proxy na magsusuri kung ang balanse ng account ay masyadong malaki. Maaaring magpasya ang manager ng bangko na maglagay ng maraming pera sa kanyang sariling account at tumakas sa Cuba gamit ang mga pondo ."

"Higit pa... Ang paglikha ng lahat ng mga chain na ito ng mga bagay ay maaaring ilagay sa isang klase ng BankFactory , kung saan maaari mong paganahin/paganahin ang mga kailangan mo."

" Gumagana ang BufferedReader gamit ang katulad na prinsipyo. Isa itong Reader , ngunit gumagawa ito ng karagdagang gawain."

"Ang diskarte na ito ay nagbibigay-daan sa iyo na «magtipon» ng isang bagay na may kinakailangang paggana mula sa iba't ibang «mga piraso»."

"Naku, muntik ko nang makalimutan. Mas malawak na ginagamit ang mga proxy kaysa sa ipinakita ko lang sa iyo. Mababasa mo ang tungkol sa iba pang gamit dito ."

Pattern ng tulay

Mga Pattern: Adapter, Proxy, Bridge - 2

"Minsan habang tumatakbo ang isang programa, kinakailangan na makabuluhang baguhin ang functionality ng isang bagay. Halimbawa, ipagpalagay na mayroon kang isang laro na may karakter ng asno na sa kalaunan ay ginawang dragon ng isang salamangkero. Ang dragon ay may ganap na magkakaibang pag-uugali at katangian, ngunit ito ay ang parehong bagay!"

"Hindi ba pwedeng gumawa na lang tayo ng bagong bagay at tapos na?"

"Hindi palagi. Ipagpalagay na ang iyong asno ay kaibigan ng isang grupo ng mga character, o marahil ito ay nasa ilalim ng impluwensya ng ilang mga spell, o ito ay kasangkot sa ilang mga pakikipagsapalaran. Sa madaling salita, ang bagay ay maaaring ginagamit na sa maraming lugar — at naka-link sa maraming iba pang mga bagay. Kaya sa kasong ito, hindi isang opsyon na gumawa ng isang bagong bagay."

"Well, ano ang maaaring gawin kung gayon?"

"Ang tulay ng tulay ay isa sa pinakamatagumpay na solusyon."

"Ang pattern na ito ay nangangailangan ng paghahati ng isang bagay sa dalawang bagay: isang «interface object» at isang «implementation object»."

"Ano ang pagkakaiba sa pagitan ng interface at ng klase na nagpapatupad nito?"

"Sa isang interface at isang klase, napupunta tayo sa isang bagay. Ngunit narito — mayroon tayong dalawa. Tingnan ang halimbawang ito:"

Halimbawa
class User
{
 private UserImpl realUser;

 public User(UserImpl impl)
 {
  realUser = impl;
 }

 public void run() //Run
 {
  realUser.run();
 }

 public void fly() //Fly
 {
  realUser.fly();
 }
}

class UserImpl
{
 public void run()
 {
 }

 public void fly()
 {
 }
}

"At pagkatapos ay maaari kang magdeklara ng ilang mga subclass ng UserImpl, halimbawa UserDonkey (donkey) at UserDragon (dragon)."

"All the same, hindi ko talaga maintindihan kung paano ito gagana."

"Well, parang ganito:"

Halimbawa
class User
{
 private UserImpl realUser;

 public User(UserImpl impl)
 {
  realUser = impl;
 }

 public void transformToDonkey()
 {
  realUser = new UserDonkeyImpl();
 }

 public void transformToDragon()
 {
  realUser = new UserDragonImpl();
 }
}
Paano ito gumagana
User user = new User(new UserDonkey()); // Internally, we're a donkey
user.transformToDragon(); // Now we're a dragon internally

"Kaya ito ay isang bagay tulad ng isang proxy."

"Oo, ngunit sa isang proxy ang pangunahing bagay ay maaaring maimbak sa isang lugar nang hiwalay, at ang code ay gumagana sa mga proxy sa halip. Dito sinasabi namin na lahat ay gumagana sa pangunahing bagay, ngunit ang mga bahagi nito ay nagbabago sa loob."

"Ah. Salamat. Bibigyan mo ba ako ng link para magbasa pa tungkol dito?"

"Siyempre, Amigo, kaibigan ko. Heto: Bridge pattern ."