solid principi

SOLID principi predstavljau 5 osnovnih principa dizajn softvera uz pomoć kojih olakšavamo razumevanje, razvoj i održavanje visokokvalitetnih i fleksibilnih softvera. 

Uz pomoć SOLID principa, težimo ka:

  1. Smanjenju kompleksnosti 
  2. Povećanju fleksibilnosti
  3. Održavanju čitljivosti i preglednosti koda

SOLID principi – prvi deo

Princip jedne odgovornosti (Single Responsibility Principle – SRP)

Klasa treba da ima samo jednu funkcionalnost (odgovornost) i samo jedan razlog za izmenu. 

Kao primer, razmatramo artikle i potrošačku korpu. Klasa Item predstavlja jedan artikal koji se dodaje u korpu prilikom kupovine. Svaki artikal ima naziv i jediničnu cenu. Ova klasa je zadužena samo za reprezentaciju jednog artikla. Logika prilikom smeštanja artikla u korpu se nalazi u klasi ShoppingCart. Klasa ShoppingCart sadrži listu artikala i metode koje rukuju sa artiklima u korpi. Metoda addItem dodaje novi artikal u korpu, dok metoda calculateTotal računa ukupnu cenu potrošnje. 

Ovim pristupom postižemo bolju organizaciju i strukturu koda, što olakšava održavanje, proširivanje i testiranje softvera. Prednosti pisanja klase po ovom principu su:

  1. Robusnost i lakše testiranje: Klasa koja ima samo jednu odgovornost je lakša za testiranje jer je lakše predvideti kako će se ponašati u različitim scenarijima. Ovo olakšava otkrivanje i ispravljanje grešaka.
  2. Manje zavisnosti: Klasa sa samo jednom odgovornosti ima manje šanse da zavisi od drugih klasa ili komponenti, što olakšava promene u kodu i smanjuje rizik od neočekivanih efekata.
  3. Bolja organizacija i preglednost: Razdvajanjem funkcionalnosti na manje delove, kod postaje bolje organizovan i lakši za razumevanje. Ovo je posebno korisno u većim projektima gde je kod kompleksniji.

Kroz ovaj pristup, čuvamo jednostavnost i jasnoću dizajna, što rezultira održivijim i skalabilnijim softverom.

import java.util.ArrayList;
import java.util.List;

// Prestavlja artikal koji se dodaje u korpu za kupovinu
class Item {
private String name;
private double price;

public Item(String name, double price) {
this.name = name;
this.price = price;
}

// Getters i setter za odgovarajuća polja
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public double getPrice() {
return price;
}

public void setPrice(double price) {
this.price = price;
}
}

// Klasa koja upravlja sa artiklima u korpi
class ShoppingCart {
private List<Item> items;

public ShoppingCart() {
this.items = new ArrayList<>();
}

public void addItem(Item item) {
items.add(item);
}

// Getters i setter za odgovarajuća polja
public List<Item> getItems() {
return items;
}

public void setItems(List<Item> items) {
this.items = items;
}

// Izračunava ukupnu potrošnju svih artikala u korpi
public double calculateTotal() {
double total = 0;
for (Item item : items) {
total += item.getPrice();
}
return total;
}
}

// Glavna klasa koja prikazuje funkcionalnosti
public class Main {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
cart.addItem(new Item("Majica", 25.99));
cart.addItem(new Item("Pantalone", 35.50));

double totalCost = cart.calculateTotal();
System.out.println("Ukupna potrošnja: $" + totalCost);
}
}

Princip otvaranja i zatvaranja (Open/Close Principle – OCP)

Softverska komponenta (klasa, funckija, itd.) treba da bude otvorena za proširenje, ali zatvorena za modifikaciju. 

Prethodni primer želimo da proširimo tako da da omogućimo postojanje artikala sa popustom. Uviđenjem nove klase DiscountItem, izbegavamo modifikaciju postojeće klase koja je prethodno testirana. Nova klasa nasleđuje klasu Item, proširujući je novim poljem koje označava iznos popusta. Takođe, dodata je metoda applyDiscount koja primenjuje popust na jediničnu cenu proizvoda. Dodatno je proširena primer sa DiscountShoppingCart klasom koja nasleđuje ShoppingCart klasu gde je redefinisana metoda calculateTotal kako bi se primenio popust na artikle koji su instance klase DiscountItem.

Ovim principom postižemo:

  1. Fleksibilnost: Softver postaje fleksibilniji jer omogućava dodavanje novih funkcionalnosti bez potrebe za izmenama u postojećem kodu.
  2. Održivost: Komponente koje su otvorene za proširenje, ali zatvorene za modifikaciju, obično su lakše za razumevanje i ne narušavaju funkcionalnosti ostalih delova sistema, što olakšava održavanje softvera.
  3. Ponovna upotrebljivost: Komponente koje su već implementirane i testirane mogu se ponovo koristiti bez potrebe za izmenama, što povećava efikasnost razvojnog procesa.

Ovim principom omogućujemo implementaciju softvera koji je lak za proširivanje, održavanje i ponovnu upotrebu, što doprinosi kvalitetu sistema.


import java.util.List;
import java.util.ArrayList;

// Prestavlja artikal koji se dodaje u korpu za kupovinu
class Item {
private String name;
private double price;

public Item(String name, double price) {
this.name = name;
this.price = price;
}

// Getters i setter za odgovarajuća polja
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public double getPrice() {
return price;
}

public void setPrice(double price) {
this.price = price;
}
}

// Klasa koja upravlja sa artiklima u korpi
class ShoppingCart {
private List<Item> items;

public ShoppingCart() {
this.items = new ArrayList<>();
}

public void addItem(Item item) {
items.add(item);
}

// Getters i setter za odgovarajuća polja
public List<Item> getItems() {
return items;
}

public void setItems(List<Item> items) {
this.items = items;
}

// Izračunava ukupnu potrošnju svih artikala u korpi
public double calculateTotal() {
double total = 0;
for (Item item : items) {
total += item.getPrice();
}
return total;
}
}

// Predstavlja artikal na popustu
class DiscountItem extends Item {
private double discount;

public DiscountItem(String name, double price, double discount) {
super(name, price);
this.discount = discount;
}

// Primenjuje se popust na cenu artikla
public double applyDiscount() {
return getPrice() * (1 - discount);
}
}

// Glavna klasa koja prikazuje funkcionalnosti
public class Main {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
cart.addItem(new Item("Majica", 25.99));
cart.addItem(new DiscountItem("Pantalone", 35.50, 0.10));

double totalCost = cart.calculateTotal();
System.out.println("Ukupna potrošnja: $" + totalCost);
}
}

// Klasa koja upravlja sa artiklima u korpi, uključujući artikle na popustu
class DiscountedShoppingCart extends ShoppingCart {
@Override
public double calculateTotal() {
double total = 0;
for (Item item : items) {
if (item instanceof DiscountItem) {
total += ((DiscountItem) item).applyDiscount();
} else {
total += item.getPrice();
}
}
return total;
}
}

// Glavna klasa koja prikazuje funkcionalnosti
public class Main {
public static void main(String[] args) {
ShoppingCart cart = new DiscountedShoppingCart();
cart.addItem(new Item("Majica", 25.99));
// Artikal sa popustom
cart.addItem(new DiscountItem("Pantalone", 35.50, 0.2));

double totalCost = cart.calculateTotal();
System.out.println("Ukupna potrosnja: $" + totalCost);
}
}