Корисник:ЛулеИзОрбите/песак
° СОЛИД је акроним коју означава пет основних принципа дизајна софтвера, осмишљених како би објектно-оријентисани дизајн био разумљивији, флексибилнији и лакши за одржавање. Ови принципи су подскуп многих принципа промовисаних од стране америчког софтверског инжењера и инструктора Роберта С. Мартина, познатијег као "Ујка Боб" (енгл. "Унцле Боб") [1][2][3], први пут представљене у његовом раду из 2000. године под називом Принципи дизајна и дизајнерски обрасци који се баве софтверском буђи.
Акроним СОЛИД је касније уведен око 2004. године од стране Мајкла Федерса[4].
Иако се СОЛИД принципи односе на било који објектно-оријентисани дизајн, такође могу да представљају основну филозофију за методологије попут агилног развоја или адаптивног софтверског развоја.
Идеје које СОЛИД обухвата су:
Принцип јединствене одговорности
[уреди | уреди извор](енгл. Сингле Респонсибилитy Принципле): "Никада не би требало да постоји више од једног разлога за промену класе."[5] Другим речима, свака класа треба да има само једну одговорност.
У овом примеру, написаном у јави програмерском језику, класа Kalkulator
у крши принципе јединствене одговорности јер осим тога што се бави логиком сабирања два броја, такође се брине о уносу и испису података.
public class Kalkulator {
public void saberi() {
Scanner scanner = new Scanner(System.in);
System.out.println("Unesite broj a");
int a = scanner.nextInt();
System.out.println("Unesite broj b");
int b = scanner.nextInt();
System.out.println("Vrednost sabiranja broja " + a + " i broja b " + b + " je " + (a + b));
}
}
Да би се класа више придржавала принципу, може се рефакторисати у нешто налик овоме
public class Kalkulator {
public int saberi(int a, int b) {
return a+b;
}
}
Сада класа Kalkulator
је одговорна само за дату логику сабирања два броја, док би се за: унос, испис итд... бринула нека друга класа.
Отворено/Затворен Принцип
[уреди | уреди извор](енгл. Опен/Цлосед Принципле): "Софтверски ентитети би требало да буду затворени за модификацију, али отворени за проширивање."[6]
У овом примеру, у случају да постоји потреба за додавањем новог начина плаћања готовином, код би морао да се дода директно у класу ProcesorPlacanja
чиме се ризикује промена већ дефинисаног понашања, тј. увођење бага.
public class ProcesorPlacanja {
public void obradiPlacanje(String tipPlacanja, double iznos) {
switch (tipPlacanja) {
case "KreditnaKartica":
obradiPlacanjeKreditnomKarticom(iznos);
break;
case "PayPal":
obradiPlacanjePayPalom(iznos);
break;
case "Bitcoin":
obradiPlacanjeBitcoinom(iznos);
break;
}
}
private void obradiPlacanjeKreditnomKarticom(double iznos) {
// Logika za plaćanje kreditnom karticom
}
private void obradiPlacanjePayPalom(double iznos) {
// Logika za plaćanje PejPalom
}
private void obradiPlacanjeBitcoinom(double iznos) {
// Logika za plaćanje Bitkoinom
}
}
Извлачењем интерфејса ProcesorPlacanja
и класа које га наслеђују PlacanjeKreditnomKarticomPlacanjePayPalom
PlacanjeBitcoinom
омогућава се лакше проширење функционалности плаћања, без икаквог утицаја на остале имплементације.
public interface ProcesorPlacanja {
void obradiPlacanje(double iznos);
}
class PlacanjeKreditnomKarticom implements ProcesorPlacanja {
@Override
public void obradiPlacanje(double iznos) {
// Logika za plaćanje kreditnom karticom
}
}
class PlacanjePayPalom implements ProcesorPlacanja {
@Override
public void obradiPlacanje(double iznos) {
// Logika za plaćanje PejPalom
}
}
class PlacanjeBitcoinom implements ProcesorPlacanja {
@Override
public void obradiPlacanje(double iznos) {
// Logika za plaćanje Bitkoin
}
}
Лисков принцип замене
[уреди | уреди извор]
(енгл. Лисков Субститутион Принципле): "Ако је класа Б поткласа класе А, прослеђивање класе Б програму који очекује класу А не сме изазвати неочекивано или недефинисано понашање"[7]. Дакле у програму који руководи класама типа Б које наслеђују класу А, не сме се задесити да се надја класа која наслеђује класу А, а не испуњава све њене фунцкионалности.
У наредном примеру постоји абстрактну класа Vozilo
коју наслеђују класе Auto
и Bicikl
и абстрактне функције zaustaviMotor()
и pokreniMotor()
. Пошто Bicikl
нема мотор, то доводи до неочекиваног понашања са програмом који би користио функције zaustaviMotor()
и pokreniMotor()
од класе Vozilo
.
abstract class Vozilo {
abstract public void idiNapred();
abstract public void pokreniMotor();
abstract public void zaustaviMotor();
abstract public int brojTockova();
}
class Auto extends Vozilo {
@Override
public void idiNapred() {
//Logika za vožnju
}
@Override
public void pokreniMotor() {
// Logika za pokretanje motora auta
}
@Override
public void zaustaviMotor() {
// Logika za zaustavljanje motora auta
}
@Override
public int brojTockova() {
return 4;
}
}
class Bicikl extends Vozilo {
@Override
public void idiNapred() {
//Logika za vožnju
}
@Override
public void pokreniMotor() {
throw new RuntimeException("Bicikl nema motor");
}
@Override
public void zaustaviMotor() {
throw new RuntimeException("Bicikl nema motor");
}
@Override
public int brojTockova() {
return 2;
}
}
Једно од могућих решења је да се од класе Vozilo
издвоји друга абстрактна класаVoziloSaMotorom
која ће наслеђивати класу Vozilo
и да се ту додају фунцкије pokreniMotor()
и zaustaviMotor()
, док би се у Vozilo
налазиле функције idiNapred()
и brojTockova()
. Класу Vozilo
би наслеђивао Bicikl
, док би класу VoziloSaMotorom
наслеђивао Auto
.
abstract class Vozilo {
abstract public void idiNapred();
abstract public int brojTockova();
}
abstract class VoziloSaMotorom extends Vozilo{
abstract public void pokreniMotor();
abstract public void zaustaviMotor();
}
class Auto extends VoziloSaMotorom {
@Override
public void idiNapred() {
//Logika za vožnju
}
@Override
public void pokreniMotor() {
// Logika za pokretanje motora auta
}
@Override
public void zaustaviMotor() {
// Logika za zaustavljanje motora auta
}
@Override
public int brojTockova() {
return 4;
}
}
class Bicikl extends Vozilo {
@Override
public void idiNapred() {
//Logika za vožnju
}
@Override
public int brojTockova() {
return 2;
}
}
Принцип сегрегације интерфејса
[уреди | уреди извор](енг.л Интерфаце Сегрегатион Принципле): "Клијенти не би требало да буду присиљени да зависе од интерфејса које не користе."[8]
У овом примеру KorisnickiServis
је приморан да имплементира и функције izvrsiUplatu()
izvrsiIsplatu()
promeniPin(int noviPIN)
чак иако клијента занима само тренутно стање рачуна.
interface BankomatServis {
void izvrsiUplatu(double iznos);
void izvrsiIsplatu(double iznos);
void prikaziStanjeRacuna();
void promeniPIN(int noviPIN);
}
class KorisnickiServis implements BankomatServis {
@Override
public void izvrsiUplatu(double iznos) {
}
@Override
public void izvrsiIsplatu(double iznos) {
}
@Override
public void prikaziStanjeRacuna() {
// Logika za prikazivanje računa
}
@Override
public void promeniPIN(int noviPIN) {
}
}
class UpravljackiServus implements BankomatServis {
@Override
public void izvrsiUplatu(double iznos) {
// Logika za uplatu
}
@Override
public void izvrsiIsplatu(double iznos) {
// Logika za isplatu
}
@Override
public void prikaziStanjeRacuna() {
// Logika za prikaz stanja računa
}
@Override
public void promeniPIN(int noviPIN) {
// Logika za PIN
}
}
Да би овај пример био прилагоðен принципу сегрегације интерфејса, може се издвојити још један интерфејс од BankomatServis
, тако да клијенти користе само оно што им је потребно.
interface UpravljackiBankomatServis {
void izvrsiUplatu(double iznos);
void izvrsiIsplatu(double iznos);
void promeniPIN(int noviPIN);
}
interface InformacionaiBankomatServis {
void prikaziStanjeRacuna();
}
class KorisnickiServis implements InformacionaiBankomatServis {
@Override
public void prikaziStanjeRacuna() {
// Logika za prikazivanje računa
}
}
class UpravljackiServis implements UpravljackiBankomatServis, InformacionaiBankomatServis {
@Override
public void izvrsiUplatu(double iznos) {
// Logika za uplatu
}
@Override
public void izvrsiIsplatu(double iznos) {
// Logika za isplatu
}
@Override
public void promeniPIN(int noviPIN) {
// Logika za PIN
}
@Override
public void prikaziStanjeRacuna() {
// Logika za prikazivanje stanja računa
}
}
Принцип инверзије зависности
[уреди | уреди извор](енгл. Депенденцy Инверсион Принципле): "Клијенти треба да зависе од апстракција, не од конкретних имплементација." [9] Ако класа А у себи садржи класу Б, класа А зависи од класе Б.
Овај принцип говори о томе да класа Б не би требало да буде конкретно нека имплементација, већ нека врсте апстракције. Што омогућава већу модуларност програма и лакшу замену имплементација у случају да дође до потребе за тим. Овај принцип је познат по томе што се често користи у потреби тестирања софтвера, јер омогућава лакшу замену правих имплементација са лажним, за потребе тестирања.
У овом примеру ако би програмер желео да замени извор корисника, из базе података у удаљени извор, то би му било отежано чињеницом да класа KorisnikServis
у себи садрзи конкретну имплементацију KorisnikBazaPodataka
.
class Korisnik {
private String ime;
private String prezime;
long id;
public Korisnik(String ime, String prezime, int id) {
this.ime = ime;
this.prezime = prezime;
this.id = id;
}
@Override
public String toString() {
return "Korisnik{" +
"ime='" + ime + '\'' +
", prezime='" + prezime + '\'' +
", id=" + id +
'}';
}
}
class KorisnikServis {
KorisnikBazaPodataka korisnikBazaPodataka = new KorisnikBazaPodataka();
public void iscitajKorisnika() {
System.out.println(korisnikBazaPodataka.dobijKorisnika(1234).toString());
}
}
class KorisnikBazaPodataka {
public Korisnik dobijKorisnika(int id) {
// Logika za čitanje korisnika iz baze
}
}
class KorisnikUdaljeniIzvoraPodataka {
public Korisnik dobijKorisnika(int id) {
// Logika za dobijanje korisnika sa nekog udaljenog izvora podataka
}
}
Да би се то избегло може да се уведе интерфејс KorisnikIzvorPodataka
који садржи функцију dobijKorisnika(int id)
које ће класе KorisnikUdaljeniIzvoraPodataka
и KorisnikBazaPodataka
да имплементирају, а класа KorisnikServis
да зависи од њега.
class Korisnik {
private String ime;
private String prezime;
long id;
public Korisnik(String ime, String prezime, int id) {
this.ime = ime;
this.prezime = prezime;
this.id = id;
}
@Override
public String toString() {
return "Korisnik{" +
"ime='" + ime + '\'' +
", prezime='" + prezime + '\'' +
", id=" + id +
'}';
}
}
class KorisnikServis {
KorisnikIzvorPodataka korisnikBazaPodataka;
public KorisnikServis(KorisnikIzvorPodataka korisnikIzvorPodataka) {
this.korisnikBazaPodataka = korisnikIzvorPodataka;
}
public void iscitajKorisnika() {
System.out.println(korisnikBazaPodataka.dobijKorisnika(1234).toString());
}
}
interface KorisnikIzvorPodataka {
public Korisnik dobijKorisnika(int id);
}
class KorisnikBazaPodataka implements KorisnikIzvorPodataka {
public Korisnik dobijKorisnika(int id) {
// Logika za čitanje korisnika iz baze
}
}
class KorisnikUdaljeniIzvoraPodataka implements KorisnikIzvorPodataka {
public Korisnik dobijKorisnika(int id) {
// Logika za dobijanje korisnika sa nekog udaljenog izvora podataka
}
}
Овим поступком се може једноставно заменити извор података у класи KorisnikServis
, и додати други ако има потребе за тим.
Види такође
[уреди | уреди извор]
Референце
[уреди | уреди извор]- ^ Мартин, Роберт C. „Принциплес Оф ООД”. БутУнцлеБоб.цом. Архивирано из оригинала 10. 9. 2014. г. Приступљено 2014-07-17. . (Референца се односи на "тхе фирст фиве принциплес", акроним СОЛИД није коришћен у овом извору.) Датира јос
- ^ Мартин, Роберт C. (13. 2. 2009). „Геттинг а СОЛИД старт”. Унцле Боб Цонсултинг ЛЛЦ (Гоогле Ситес). Архивирано из оригинала 17. 9. 2013. г. Приступљено 2013-08-19.
- ^ Метз, Санди (мај 2009). „СОЛИД Објецт-Ориентед Десигн”. YоуТубе. Архивирано из оригинала 2021-12-21. г. Приступљено 2019-08-13. Говор одржан 2009. године на Готам Рубy Конференцији.
- ^ Мартин, Роберт (2018). Цлеан Арцхитецтуре: А Црафтсман'с Гуиде то Софтwаре Струцтуре анд Десигн. стр. 58. ИСБН 9780134494166.
- ^ „Сингле Респонсибилитy Принципле” (ПДФ). објецтментор.цом. Архивирано из оригинала 2. 2. 2015. г.
- ^ https://www.cs.utexas.edu/users/downing/papers/OCP-1996.pdf
- ^ https://www.cs.utexas.edu/users/downing/papers/LSP-1996.pdf
- ^ https://condor.depaul.edu/dmumaugh/OOT/Design-Principles/isp.pdf
- ^ https://www.engr.mun.ca/~theo/Courses/sd/5895-downloads/sd-principles-4.ppt.pdf