├── .gitignore ├── README.md ├── pom.xml └── src └── main └── java └── com └── techtong └── solid ├── dip ├── refactored │ ├── Main.java │ ├── models │ │ ├── Customer.java │ │ └── ShoppingCart.java │ └── services │ │ ├── NewCheckoutService.java │ │ ├── NewSmsService.java │ │ └── sms │ │ ├── GpSmsProvider.java │ │ ├── RobiSmsProvider.java │ │ └── SmsProvider.java └── violation │ ├── Main.java │ ├── models │ ├── Customer.java │ └── ShoppingCart.java │ └── services │ ├── CheckoutService.java │ └── SmsService.java ├── isp ├── refactored │ ├── Main.java │ └── account │ │ ├── BaseAccount.java │ │ ├── InternationalAmountTransferable.java │ │ ├── RemittanceSavingsAccount.java │ │ ├── SavingsAccount.java │ │ └── StudentAccount.java └── violation │ ├── Main.java │ └── account │ ├── RemittanceSavingsAccount.java │ ├── SavingsAccount.java │ └── StudentAccount.java ├── lsp ├── refactored │ ├── Main.java │ └── model │ │ ├── ContractEmployee.java │ │ ├── Employee.java │ │ ├── EmployeeBonusEligible.java │ │ ├── IEmployee.java │ │ ├── PermanentEmployee.java │ │ └── TemporaryEmployee.java └── violation │ ├── Main.java │ └── model │ ├── ContractEmployee.java │ ├── Employee.java │ ├── PermanentEmployee.java │ └── TemporaryEmployee.java ├── ocp ├── OCP.java ├── refactored │ ├── DecentKitchenService.java │ ├── FoodPreparer.java │ └── models │ │ ├── BakedFood.java │ │ ├── FoodItem.java │ │ ├── FriedFood.java │ │ ├── GrilledFood.java │ │ └── SauteedFood.java └── violation │ ├── BadKitchenService.java │ └── models │ ├── FoodItem.java │ ├── FriedFood.java │ └── GrilledFood.java └── srp ├── refactored ├── Customer.java ├── Item.java ├── Main.java ├── logger │ ├── ConsoleLogger.java │ ├── FileLogger.java │ └── Logger.java └── pricecalculation │ ├── ItemPriceCalculationService.java │ └── TaxCalculationService.java └── violation ├── Customer.java ├── Item.java └── Main.java /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | 3 | *.iml 4 | 5 | # Compiled class file 6 | *.class 7 | 8 | # Log file 9 | *.log 10 | 11 | # BlueJ files 12 | *.ctxt 13 | 14 | # Mobile Tools for Java (J2ME) 15 | .mtj.tmp/ 16 | 17 | # Package Files # 18 | *.jar 19 | *.war 20 | *.nar 21 | *.ear 22 | *.zip 23 | *.tar.gz 24 | *.rar 25 | 26 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 27 | hs_err_pid* 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Solid Principles 2 | 3 | This repository contains codes for the first deep dive series on Solid Principles. 4 | 5 | - Code related to a principle has its own package under solid. 6 | - Principle violated code will be under the violated package, and refactored one will under the refactored package. 7 | - If you feel we could do better in refactoring, don't forget to create a PR with your changes 8 | - If you have any feedback, please email us at techtongbd@gmail.com 9 | 10 | License 11 | ---- 12 | 13 | MIT 14 | 15 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.techtong 8 | solid-principles 9 | 1.0.0 10 | 11 | 12 | 13 | org.apache.maven.plugins 14 | maven-compiler-plugin 15 | 16 | 10 17 | 10 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/refactored/Main.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.refactored; 2 | 3 | import com.techtong.solid.dip.refactored.models.Customer; 4 | import com.techtong.solid.dip.refactored.models.ShoppingCart; 5 | import com.techtong.solid.dip.refactored.services.NewCheckoutService; 6 | import com.techtong.solid.dip.refactored.services.NewSmsService; 7 | import com.techtong.solid.dip.refactored.services.sms.GpSmsProvider; 8 | import com.techtong.solid.dip.refactored.services.sms.RobiSmsProvider; 9 | import com.techtong.solid.dip.refactored.services.sms.SmsProvider; 10 | 11 | public class Main { 12 | public static void main(String[] args) { 13 | Customer customer = new Customer("Sabbir Siddiqui", "01717111111"); 14 | ShoppingCart shoppingCart = new ShoppingCart(1200, customer); 15 | 16 | SmsProvider smsProvider = new RobiSmsProvider(); 17 | // SmsProvider smsProvider = new GpSmsProvider(); 18 | NewSmsService smsService = new NewSmsService(smsProvider); 19 | NewCheckoutService checkoutService = new NewCheckoutService(smsService); 20 | 21 | checkoutService.checkout(shoppingCart); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/refactored/models/Customer.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.refactored.models; 2 | 3 | public class Customer { 4 | private String fullName; 5 | private String phoneNumber; 6 | 7 | public Customer(String fullName, String phoneNumber) { 8 | this.fullName = fullName; 9 | this.phoneNumber = phoneNumber; 10 | } 11 | 12 | public String getFullName() { 13 | return fullName; 14 | } 15 | 16 | public void setFullName(String fullName) { 17 | this.fullName = fullName; 18 | } 19 | 20 | public String getPhoneNumber() { 21 | return phoneNumber; 22 | } 23 | 24 | public void setPhoneNumber(String phoneNumber) { 25 | this.phoneNumber = phoneNumber; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/refactored/models/ShoppingCart.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.refactored.models; 2 | 3 | public class ShoppingCart { 4 | private double totalAmount; 5 | private Customer customer; 6 | 7 | public ShoppingCart(double totalAmount, Customer customer) { 8 | this.totalAmount = totalAmount; 9 | this.customer = customer; 10 | } 11 | 12 | public double getTotalAmount() { 13 | return totalAmount; 14 | } 15 | 16 | public void setTotalAmount(double totalAmount) { 17 | this.totalAmount = totalAmount; 18 | } 19 | 20 | public Customer getCustomer() { 21 | return customer; 22 | } 23 | 24 | public void setCustomer(Customer customer) { 25 | this.customer = customer; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/refactored/services/NewCheckoutService.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.refactored.services; 2 | 3 | import com.techtong.solid.dip.refactored.models.ShoppingCart; 4 | 5 | public class NewCheckoutService { 6 | private final NewSmsService newSmsService; 7 | 8 | public NewCheckoutService(NewSmsService newSmsService) { 9 | this.newSmsService = newSmsService; 10 | } 11 | 12 | private void sendConfirmationSms(ShoppingCart shoppingCart) { 13 | final String message = "Thank you, " + shoppingCart.getCustomer().getFullName() + " for shopping at our store." + 14 | "\nYour order of total BDT " + shoppingCart.getTotalAmount() + " has been confirmed."; 15 | 16 | newSmsService.sendSms(message, shoppingCart.getCustomer().getPhoneNumber()); 17 | } 18 | 19 | public void checkout(ShoppingCart shoppingCart) { 20 | // do some other stuff here 21 | System.out.println("Checking out " + shoppingCart.getCustomer().getFullName()); 22 | // send sms 23 | sendConfirmationSms(shoppingCart); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/refactored/services/NewSmsService.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.refactored.services; 2 | 3 | import com.techtong.solid.dip.refactored.services.sms.SmsProvider; 4 | 5 | public class NewSmsService { 6 | private SmsProvider smsProvider; 7 | 8 | public NewSmsService(SmsProvider smsProvider) { 9 | this.smsProvider = smsProvider; 10 | } 11 | 12 | void sendSms(String text, String phoneNumber) { 13 | smsProvider.sendSms(phoneNumber, text); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/refactored/services/sms/GpSmsProvider.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.refactored.services.sms; 2 | 3 | public class GpSmsProvider implements SmsProvider { 4 | @Override 5 | public void sendSms(String phoneNumber, String text) { 6 | System.out.println("Sending SMS via GP:"); 7 | System.out.println("----> Receiver: " + phoneNumber); 8 | System.out.println("----> Text:\n" + text); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/refactored/services/sms/RobiSmsProvider.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.refactored.services.sms; 2 | 3 | public class RobiSmsProvider implements SmsProvider { 4 | @Override 5 | public void sendSms(String phoneNumber, String text) { 6 | System.out.println("Sending SMS via Robi:"); 7 | System.out.println("----> Receiver: " + phoneNumber); 8 | System.out.println("----> Text:\n" + text); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/refactored/services/sms/SmsProvider.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.refactored.services.sms; 2 | 3 | public interface SmsProvider { 4 | void sendSms(String phoneNumber, String text); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/violation/Main.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.violation; 2 | 3 | import com.techtong.solid.dip.violation.models.Customer; 4 | import com.techtong.solid.dip.violation.models.ShoppingCart; 5 | import com.techtong.solid.dip.violation.services.CheckoutService; 6 | 7 | public class Main { 8 | public static void main(String[] args) { 9 | Customer customer = new Customer("Sabbir Siddiqui", "01717111111"); 10 | ShoppingCart shoppingCart = new ShoppingCart(1200, customer); 11 | 12 | CheckoutService checkoutService = new CheckoutService(); 13 | 14 | checkoutService.checkout(shoppingCart); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/violation/models/Customer.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.violation.models; 2 | 3 | public class Customer { 4 | private String fullName; 5 | private String phoneNumber; 6 | 7 | public Customer(String fullName, String phoneNumber) { 8 | this.fullName = fullName; 9 | this.phoneNumber = phoneNumber; 10 | } 11 | 12 | public String getFullName() { 13 | return fullName; 14 | } 15 | 16 | public void setFullName(String fullName) { 17 | this.fullName = fullName; 18 | } 19 | 20 | public String getPhoneNumber() { 21 | return phoneNumber; 22 | } 23 | 24 | public void setPhoneNumber(String phoneNumber) { 25 | this.phoneNumber = phoneNumber; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/violation/models/ShoppingCart.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.violation.models; 2 | 3 | public class ShoppingCart { 4 | private double totalAmount; 5 | private Customer customer; 6 | 7 | public ShoppingCart(double totalAmount, Customer customer) { 8 | this.totalAmount = totalAmount; 9 | this.customer = customer; 10 | } 11 | 12 | public double getTotalAmount() { 13 | return totalAmount; 14 | } 15 | 16 | public void setTotalAmount(double totalAmount) { 17 | this.totalAmount = totalAmount; 18 | } 19 | 20 | public Customer getCustomer() { 21 | return customer; 22 | } 23 | 24 | public void setCustomer(Customer customer) { 25 | this.customer = customer; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/violation/services/CheckoutService.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.violation.services; 2 | 3 | import com.techtong.solid.dip.violation.models.ShoppingCart; 4 | 5 | public class CheckoutService { 6 | private final SmsService smsService; 7 | 8 | public CheckoutService() { 9 | this.smsService = new SmsService(); 10 | } 11 | 12 | private void sendConfirmationSms(ShoppingCart shoppingCart) { 13 | final String message = "Thank you, " + shoppingCart.getCustomer().getFullName() + " for shopping at our store." + 14 | "\nYour order of total BDT " + shoppingCart.getTotalAmount() + " has been confirmed."; 15 | 16 | smsService.sendSms(message, shoppingCart.getCustomer().getPhoneNumber()); 17 | } 18 | 19 | public void checkout(ShoppingCart shoppingCart) { 20 | // do some other stuff here 21 | System.out.println("Checking out " + shoppingCart.getCustomer().getFullName()); 22 | // send sms 23 | sendConfirmationSms(shoppingCart); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/dip/violation/services/SmsService.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.dip.violation.services; 2 | 3 | public class SmsService { 4 | void sendSms(String text, String phoneNumber) { 5 | System.out.println("Sending SMS via GP:"); 6 | System.out.println("----> Receiver: " + phoneNumber); 7 | System.out.println("----> Text:\n" + text); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/isp/refactored/Main.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.isp.refactored; 2 | 3 | 4 | import com.techtong.solid.isp.refactored.account.RemittanceSavingsAccount; 5 | import com.techtong.solid.isp.refactored.account.StudentAccount; 6 | 7 | public class Main { 8 | 9 | public static void main(String[] args) { 10 | 11 | RemittanceSavingsAccount remittanceSavingsAccount = new RemittanceSavingsAccount( 12 | 1, 13 | "Rahim", 14 | 100, 15 | "Italy"); 16 | 17 | remittanceSavingsAccount.creditLocalAmount(100); 18 | remittanceSavingsAccount.creditInternationalAmount(10); 19 | 20 | System.out.println(remittanceSavingsAccount.getBalance()); 21 | 22 | 23 | StudentAccount studentAccount = new StudentAccount( 24 | 1, 25 | "Karim", 26 | 100, 27 | "BUET"); 28 | 29 | studentAccount.creditLocalAmount(100); 30 | 31 | System.out.println(studentAccount.getBalance()); 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/isp/refactored/account/BaseAccount.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.isp.refactored.account; 2 | 3 | public class BaseAccount { 4 | protected int accountId; 5 | protected String accountName; 6 | protected double balance; 7 | 8 | public BaseAccount(int accountId, String accountName, double balance) { 9 | this.accountId = accountId; 10 | this.accountName = accountName; 11 | this.balance = balance; 12 | } 13 | 14 | public double getBalance() { 15 | return balance; 16 | } 17 | 18 | public void setBalance(double balance) { 19 | this.balance = balance; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/isp/refactored/account/InternationalAmountTransferable.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.isp.refactored.account; 2 | 3 | public interface InternationalAmountTransferable { 4 | public void creditInternationalAmount(double amountInUSD); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/isp/refactored/account/RemittanceSavingsAccount.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.isp.refactored.account; 2 | 3 | public class RemittanceSavingsAccount extends BaseAccount implements SavingsAccount, InternationalAmountTransferable { 4 | private String primarySourceCountry; 5 | 6 | public RemittanceSavingsAccount(int accountId, 7 | String accountName, 8 | double balance, 9 | String primarySourceCountry) { 10 | super(accountId, accountName, balance); 11 | this.primarySourceCountry = primarySourceCountry; 12 | } 13 | 14 | @Override 15 | public double getBalance() { 16 | return this.balance; 17 | } 18 | 19 | @Override 20 | public void creditLocalAmount(double amountInBDT) { 21 | this.balance += amountInBDT; 22 | } 23 | 24 | @Override 25 | public void creditInternationalAmount(double amountInUSD) { 26 | double amountInBDT = amountInUSD * 86; 27 | double incentiveAmount = amountInBDT * 0.02; 28 | this.balance += amountInBDT + incentiveAmount; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/isp/refactored/account/SavingsAccount.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.isp.refactored.account; 2 | 3 | public interface SavingsAccount { 4 | public double getBalance(); 5 | 6 | public void creditLocalAmount(double amountInBDT); 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/isp/refactored/account/StudentAccount.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.isp.refactored.account; 2 | 3 | public class StudentAccount extends BaseAccount implements SavingsAccount { 4 | private String institutionName; 5 | 6 | public StudentAccount(int accountId, 7 | String accountName, 8 | double balance, 9 | String institutionName) { 10 | super(accountId, accountName, balance); 11 | this.institutionName = institutionName; 12 | } 13 | 14 | @Override 15 | public void creditLocalAmount(double amountInBDT) { 16 | this.balance += amountInBDT; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/isp/violation/Main.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.isp.violation; 2 | 3 | import com.techtong.solid.isp.violation.account.RemittanceSavingsAccount; 4 | import com.techtong.solid.isp.violation.account.StudentAccount; 5 | 6 | public class Main { 7 | 8 | public static void main(String[] args) { 9 | 10 | RemittanceSavingsAccount remittanceSavingsAccount = new RemittanceSavingsAccount( 11 | 1, 12 | "Rahim", 13 | 100, 14 | "Italy"); 15 | 16 | remittanceSavingsAccount.creditLocalAmount(100); 17 | remittanceSavingsAccount.creditInternationalAmount(10); 18 | 19 | System.out.println(remittanceSavingsAccount.getBalance()); 20 | 21 | 22 | StudentAccount studentAccount = new StudentAccount( 23 | 1, 24 | "Karim", 25 | 100, 26 | "BUET"); 27 | 28 | studentAccount.creditLocalAmount(100); 29 | studentAccount.creditInternationalAmount(10); 30 | 31 | System.out.println(studentAccount.getBalance()); 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/isp/violation/account/RemittanceSavingsAccount.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.isp.violation.account; 2 | 3 | import com.techtong.solid.isp.refactored.account.BaseAccount; 4 | 5 | public class RemittanceSavingsAccount extends BaseAccount implements SavingsAccount { 6 | private String primarySourceCountry; 7 | 8 | public RemittanceSavingsAccount(int accountId, 9 | String accountName, 10 | double balance, 11 | String primarySourceCountry) { 12 | super(accountId, accountName, balance); 13 | this.primarySourceCountry = primarySourceCountry; 14 | } 15 | 16 | @Override 17 | public double getBalance() { 18 | return this.balance; 19 | } 20 | 21 | @Override 22 | public void creditLocalAmount(double amountInBDT) { 23 | this.balance += amountInBDT; 24 | } 25 | 26 | @Override 27 | public void creditInternationalAmount(double amountInUSD) { 28 | double amountInBDT = amountInUSD * 86; 29 | double incentiveAmount = amountInBDT * 0.02; 30 | this.balance += amountInBDT + incentiveAmount; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/isp/violation/account/SavingsAccount.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.isp.violation.account; 2 | 3 | public interface SavingsAccount { 4 | public double getBalance(); 5 | 6 | public void creditLocalAmount(double amountInBDT); 7 | 8 | public void creditInternationalAmount(double amountInUSD); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/isp/violation/account/StudentAccount.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.isp.violation.account; 2 | 3 | import com.techtong.solid.isp.refactored.account.BaseAccount; 4 | 5 | public class StudentAccount extends BaseAccount implements SavingsAccount { 6 | private String institutionName; 7 | 8 | public StudentAccount(int accountId, 9 | String accountName, 10 | double balance, 11 | String institutionName) { 12 | super(accountId, accountName, balance); 13 | this.institutionName = institutionName; 14 | } 15 | 16 | @Override 17 | public void creditLocalAmount(double amountInBDT) { 18 | this.balance += amountInBDT; 19 | } 20 | 21 | @Override 22 | public void creditInternationalAmount(double amountInUSD) { 23 | throw new UnsupportedOperationException("International amount transfer is not applicable for student account"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/lsp/refactored/Main.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.lsp.refactored; 2 | 3 | 4 | import com.techtong.solid.lsp.refactored.model.*; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.logging.Level; 9 | import java.util.logging.Logger; 10 | 11 | public class Main { 12 | private final static Logger LOGGER = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME) ; 13 | 14 | public static void main(String[] args){ 15 | List employees = List.of( 16 | new PermanentEmployee(1, "Sabbir"), 17 | new TemporaryEmployee(2, "Sazzad")); 18 | 19 | for( EmployeeBonusEligible employee : employees ){ 20 | System.out.println(employee.toString() + " Employee Bonus : " + employee.calculateBonus(1000)); 21 | } 22 | 23 | System.out.println("----------"); 24 | List employeesOnly = List.of( 25 | new PermanentEmployee(1, "Sabbir"), 26 | new TemporaryEmployee(2, "Sazzad"), 27 | new ContractEmployee(3, "Abcdef") 28 | ); 29 | 30 | for( IEmployee employee : employeesOnly ){ 31 | System.out.println(employee.toString() + " Employee is eligible for Insurance : " + employee.isEligibleForInsurance()); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/lsp/refactored/model/ContractEmployee.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.lsp.refactored.model; 2 | 3 | public class ContractEmployee extends Employee { 4 | 5 | public ContractEmployee(int id, String name) { 6 | super(id,name); 7 | } 8 | 9 | public boolean isEligibleForInsurance() { 10 | return false; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/lsp/refactored/model/Employee.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.lsp.refactored.model; 2 | 3 | public abstract class Employee implements IEmployee { 4 | private final int id; 5 | private final String name; 6 | 7 | public int getId() { 8 | return id; 9 | } 10 | public String getName() { 11 | return name; 12 | } 13 | 14 | public Employee(int id, String name){ 15 | this.id = id; 16 | this.name = name; 17 | } 18 | @Override 19 | public String toString() { 20 | return "Employee ID: " + this.getId() + " Employee Name : " + this.getName(); 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/lsp/refactored/model/EmployeeBonusEligible.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.lsp.refactored.model; 2 | 3 | public interface EmployeeBonusEligible { 4 | double calculateBonus(double salary); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/lsp/refactored/model/IEmployee.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.lsp.refactored.model; 2 | 3 | public interface IEmployee { 4 | boolean isEligibleForInsurance(); 5 | } 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/lsp/refactored/model/PermanentEmployee.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.lsp.refactored.model; 2 | 3 | 4 | public class PermanentEmployee extends Employee implements EmployeeBonusEligible { 5 | 6 | public PermanentEmployee(int id, String name) { 7 | super(id, name); 8 | } 9 | 10 | @Override 11 | public double calculateBonus(double salary) { 12 | return salary * .1; 13 | } 14 | 15 | @Override 16 | public boolean isEligibleForInsurance() { 17 | return true; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/lsp/refactored/model/TemporaryEmployee.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.lsp.refactored.model; 2 | 3 | public class TemporaryEmployee extends Employee implements EmployeeBonusEligible{ 4 | 5 | public TemporaryEmployee(int id, String name) { 6 | super(id, name); 7 | } 8 | 9 | @Override 10 | public double calculateBonus(double salary) { 11 | return salary * .05; 12 | } 13 | 14 | public boolean isEligibleForInsurance() { 15 | return false; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/lsp/violation/Main.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.lsp.violation; 2 | 3 | import com.techtong.solid.lsp.violation.model.ContractEmployee; 4 | import com.techtong.solid.lsp.violation.model.Employee; 5 | import com.techtong.solid.lsp.violation.model.PermanentEmployee; 6 | import com.techtong.solid.lsp.violation.model.TemporaryEmployee; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.logging.Level; 11 | import java.util.logging.Logger; 12 | 13 | public class Main { 14 | private final static Logger LOGGER = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME) ; 15 | 16 | public static void main(String[] args){ 17 | List employees = new ArrayList<>(); 18 | employees.add( new PermanentEmployee(1, "Sabbir")); 19 | employees.add( new TemporaryEmployee(2, "Sazzad")); 20 | employees.add( new ContractEmployee(3, "Abc")); 21 | 22 | for( Employee employee : employees ) { 23 | 24 | System.out.println("Employee ID: " + employee.getId() + " Employee Name : " + employee.getName() + " - Employee is eligible for Insurance : " + employee.isEligibleForInsurance()); 25 | } 26 | 27 | System.out.println("--------------------"); 28 | 29 | for( Employee employee : employees ){ 30 | try { 31 | System.out.println("Employee ID: " + employee.getId() + " Employee Name : " + employee.getName() + " Employee Bonus : " + employee.calculateBonus(1000)); 32 | }catch (UnsupportedOperationException exception) { 33 | LOGGER.log(Level.SEVERE, " This employee is not eligible for bonus"); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/lsp/violation/model/ContractEmployee.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.lsp.violation.model; 2 | 3 | public class ContractEmployee extends Employee{ 4 | 5 | public ContractEmployee(int id, String name) { 6 | super(id, name); 7 | } 8 | 9 | @Override 10 | public boolean isEligibleForInsurance() { 11 | return false; 12 | } 13 | 14 | @Override 15 | public double calculateBonus(float salary) { 16 | throw new UnsupportedOperationException("Not implemented"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/lsp/violation/model/Employee.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.lsp.violation.model; 2 | 3 | public abstract class Employee { 4 | private final int id; 5 | private final String name; 6 | 7 | public int getId() { 8 | return id; 9 | } 10 | 11 | public String getName() { 12 | return name; 13 | } 14 | 15 | public Employee(int id, String name){ 16 | this.id = id; 17 | this.name = name; 18 | } 19 | public abstract double calculateBonus(float salary); 20 | public abstract boolean isEligibleForInsurance(); 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/lsp/violation/model/PermanentEmployee.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.lsp.violation.model; 2 | 3 | public class PermanentEmployee extends Employee{ 4 | 5 | public PermanentEmployee(int id, String name) { 6 | super(id, name); 7 | } 8 | 9 | @Override 10 | public boolean isEligibleForInsurance() { 11 | return true; 12 | } 13 | 14 | @Override 15 | public double calculateBonus(float salary) { 16 | return salary * .1; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/lsp/violation/model/TemporaryEmployee.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.lsp.violation.model; 2 | 3 | public class TemporaryEmployee extends Employee{ 4 | 5 | public TemporaryEmployee(int id, String name) { 6 | super(id, name); 7 | } 8 | 9 | @Override 10 | public boolean isEligibleForInsurance() { 11 | return false; 12 | } 13 | 14 | @Override 15 | public double calculateBonus(float salary) { 16 | return salary * .05; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/ocp/OCP.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.ocp; 2 | 3 | import com.techtong.solid.ocp.violation.models.FoodItem; 4 | import com.techtong.solid.ocp.violation.models.FriedFood; 5 | import com.techtong.solid.ocp.violation.models.GrilledFood; 6 | import com.techtong.solid.ocp.violation.BadKitchenService; 7 | 8 | import java.util.List; 9 | 10 | public class OCP { 11 | public static void main(String[] args) { 12 | 13 | List foodItems = List.of( 14 | new GrilledFood("steak"), 15 | new FriedFood("chicken") 16 | ); 17 | 18 | BadKitchenService kitchenService = new BadKitchenService(); 19 | 20 | System.out.println("Preparing Items:"); 21 | kitchenService.prepareItems(foodItems); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/ocp/refactored/DecentKitchenService.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.ocp.refactored; 2 | 3 | import com.techtong.solid.ocp.refactored.models.FoodItem; 4 | 5 | import java.util.List; 6 | 7 | public class DecentKitchenService { 8 | public void prepareItems(List foodItems) { 9 | foodItems.forEach(FoodPreparer::prepare); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/ocp/refactored/FoodPreparer.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.ocp.refactored; 2 | 3 | public interface FoodPreparer { 4 | public void prepare(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/ocp/refactored/models/BakedFood.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.ocp.refactored.models; 2 | 3 | import com.techtong.solid.ocp.refactored.FoodPreparer; 4 | 5 | public class BakedFood extends FoodItem implements FoodPreparer { 6 | public BakedFood(String name) { 7 | super(name); 8 | } 9 | 10 | @Override 11 | public void prepare() { 12 | System.out.println("---> Baking " + this.getName()); // some grilling logic 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/ocp/refactored/models/FoodItem.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.ocp.refactored.models; 2 | 3 | import com.techtong.solid.ocp.refactored.FoodPreparer; 4 | 5 | public abstract class FoodItem implements FoodPreparer { 6 | private String name; 7 | 8 | public FoodItem(String name) { 9 | this.name = name; 10 | } 11 | 12 | public String getName() { 13 | return name; 14 | } 15 | 16 | public void setName(String name) { 17 | this.name = name; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/ocp/refactored/models/FriedFood.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.ocp.refactored.models; 2 | 3 | public class FriedFood extends FoodItem { 4 | public FriedFood(String name) { 5 | super(name); 6 | } 7 | 8 | @Override 9 | public void prepare() { 10 | System.out.println("====> Frying " + this.getName()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/ocp/refactored/models/GrilledFood.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.ocp.refactored.models; 2 | 3 | public class GrilledFood extends FoodItem { 4 | public GrilledFood(String name) { 5 | super(name); 6 | } 7 | 8 | @Override 9 | public void prepare() { 10 | System.out.println("====> Grilling " + this.getName()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/ocp/refactored/models/SauteedFood.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.ocp.refactored.models; 2 | 3 | import com.techtong.solid.ocp.refactored.FoodPreparer; 4 | import com.techtong.solid.ocp.violation.models.FoodItem; 5 | 6 | public class SauteedFood extends FoodItem implements FoodPreparer { 7 | public SauteedFood(String name) { 8 | super(name); 9 | } 10 | 11 | @Override 12 | public void prepare() { 13 | System.out.println("---> Sauteeing " + this.getName()); // some grilling logic 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/ocp/violation/BadKitchenService.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.ocp.violation; 2 | 3 | import com.techtong.solid.ocp.violation.models.FoodItem; 4 | import com.techtong.solid.ocp.violation.models.FriedFood; 5 | import com.techtong.solid.ocp.violation.models.GrilledFood; 6 | 7 | import java.util.List; 8 | 9 | public class BadKitchenService { 10 | public void prepareItems(List foodItems) { 11 | for (final FoodItem foodItem : foodItems) { 12 | if (foodItem instanceof GrilledFood) { 13 | System.out.println("---> Grilling " + foodItem.getName()); 14 | } 15 | 16 | if (foodItem instanceof FriedFood) { 17 | System.out.println("---> Frying " + foodItem.getName()); 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/ocp/violation/models/FoodItem.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.ocp.violation.models; 2 | 3 | public abstract class FoodItem { 4 | private String name; 5 | 6 | public FoodItem(String name) { 7 | this.name = name; 8 | } 9 | 10 | public String getName() { 11 | return name; 12 | } 13 | 14 | public void setName(String name) { 15 | this.name = name; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/ocp/violation/models/FriedFood.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.ocp.violation.models; 2 | 3 | public class FriedFood extends FoodItem { 4 | public FriedFood(String name) { 5 | super(name); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/ocp/violation/models/GrilledFood.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.ocp.violation.models; 2 | 3 | public class GrilledFood extends FoodItem { 4 | public GrilledFood(String name) { 5 | super(name); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/srp/refactored/Customer.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.srp.refactored; 2 | 3 | public class Customer { 4 | private final String name; 5 | private final int age; 6 | 7 | public Customer(String name, int age) { 8 | this.name = name; 9 | this.age = age; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/srp/refactored/Item.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.srp.refactored; 2 | 3 | public class Item { 4 | private String name; 5 | private Double price; 6 | 7 | public Item(String name, Double price) { 8 | this.name = name; 9 | this.price = price; 10 | } 11 | 12 | public String getName() { 13 | return name; 14 | } 15 | 16 | public void setName(String name) { 17 | this.name = name; 18 | } 19 | 20 | public Double getPrice() { 21 | return price; 22 | } 23 | 24 | public void setPrice(Double price) { 25 | this.price = price; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/srp/refactored/Main.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.srp.refactored; 2 | 3 | import com.techtong.solid.srp.refactored.pricecalculation.ItemPriceCalculationService; 4 | 5 | import java.util.List; 6 | 7 | public class Main { 8 | 9 | public static void main(String[] args) { 10 | Item cleanCodeBook = new Item("Clean Code", 100.0); 11 | Item mask = new Item("Mask", 10.0); 12 | Item tShirt = new Item("Mask", 20.0); 13 | 14 | int plasticBagTaken = 2; 15 | int tax = 10; 16 | 17 | List itemsPurchased = List.of(cleanCodeBook, mask, tShirt); 18 | 19 | ItemPriceCalculationService itemPriceCalculation = new ItemPriceCalculationService(); 20 | 21 | double totalPriceOfItems = itemPriceCalculation.calculateItemPrice(itemsPurchased, 22 | plasticBagTaken, 23 | tax); 24 | 25 | System.out.println("Total Prices of items purchased : " + totalPriceOfItems); 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/srp/refactored/logger/ConsoleLogger.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.srp.refactored.logger; 2 | 3 | public class ConsoleLogger { 4 | public void logInConsole(String message) { 5 | System.out.println("Console Log : " + message); 6 | } 7 | } -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/srp/refactored/logger/FileLogger.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.srp.refactored.logger; 2 | 3 | public class FileLogger { 4 | public void logInFile(String message) { 5 | System.out.println("File Log: " + message); 6 | } 7 | } -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/srp/refactored/logger/Logger.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.srp.refactored.logger; 2 | 3 | public class Logger { 4 | 5 | private static final FileLogger fileLogger = new FileLogger(); 6 | private static final ConsoleLogger consoleLogger = new ConsoleLogger(); 7 | 8 | public static void info(String message) { 9 | fileLogger.logInFile(message); 10 | consoleLogger.logInConsole(message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/srp/refactored/pricecalculation/ItemPriceCalculationService.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.srp.refactored.pricecalculation; 2 | 3 | import com.techtong.solid.srp.refactored.Item; 4 | import com.techtong.solid.srp.refactored.logger.Logger; 5 | 6 | import java.util.List; 7 | 8 | public class ItemPriceCalculationService { 9 | private double plasticBagPrice = 2.0; 10 | private final TaxCalculationService taxCalculationService = new TaxCalculationService(); 11 | 12 | public double calculateItemPrice(List items, 13 | int numberOfPlasticBags, 14 | int tax) { 15 | double itemPrices = getTotalItemPrices(items); 16 | calculatePlasticBagPrice(items.size()); 17 | 18 | double totalTax = taxCalculationService.calculateTax(itemPrices, tax); 19 | 20 | double totalPrice = itemPrices + totalTax + numberOfPlasticBags * plasticBagPrice; 21 | Logger.info("Total Price of the items -> " + totalPrice); 22 | return totalPrice; 23 | } 24 | 25 | public double getTotalItemPrices(List items) { 26 | return items 27 | .stream() 28 | .mapToDouble(Item::getPrice) 29 | .sum(); 30 | } 31 | 32 | public void calculatePlasticBagPrice(int totalItems) { 33 | if (totalItems > 2) { 34 | plasticBagPrice = plasticBagPrice * 0.5; 35 | Logger.info("More than 2 items purchased. Reducing plastic bag price"); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/srp/refactored/pricecalculation/TaxCalculationService.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.srp.refactored.pricecalculation; 2 | 3 | import com.techtong.solid.srp.refactored.logger.Logger; 4 | 5 | public class TaxCalculationService { 6 | 7 | public double calculateTax(double itemPrice, double tax) { 8 | if (itemPrice <= 100) { 9 | Logger.info("Item price is more than 100. 80 Percent of the actual tax applicable"); 10 | tax = tax * .80; 11 | } else if (itemPrice >= 100 && itemPrice <= 150) { 12 | Logger.info("Item price is more than 100 but less than 150. 90 Percent of the actual tax applicable"); 13 | tax = tax * .90; 14 | } 15 | return tax; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/srp/violation/Customer.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.srp.violation; 2 | 3 | import java.util.List; 4 | 5 | public class Customer { 6 | private final String name; 7 | private final int age; 8 | private final List items; 9 | private final int numberOfPlasticBags; 10 | private double plasticBagPrice = 2.00; 11 | 12 | public Customer(String name, int age, List items, int numberOfPlasticBags) { 13 | this.name = name; 14 | this.age = age; 15 | this.items = items; 16 | this.numberOfPlasticBags = numberOfPlasticBags; 17 | } 18 | 19 | public double calculatePrice(double tax) { 20 | int totalItems = items.size(); 21 | double itemPrice = items 22 | .stream() 23 | .mapToDouble(Item::getPrice) 24 | .sum(); 25 | 26 | if (totalItems > 2) { 27 | plasticBagPrice = plasticBagPrice * 0.5; 28 | logInformation("More than 2 items purchased. Reducing plastic bag price"); 29 | } 30 | 31 | if (itemPrice <= 100) { 32 | logInformation("Item price is more than 100. 80 Percent of the actual tax applicable"); 33 | tax = tax * .80; 34 | } else if (itemPrice >= 100 && itemPrice <= 150) { 35 | logInformation("Item price is more than 100 but less than 150. 90 Percent of the actual tax applicable"); 36 | tax = tax * .90; 37 | } 38 | double totalPrice = itemPrice + tax + this.numberOfPlasticBags * plasticBagPrice; 39 | logInformation("Total Price of the items -> " + totalPrice); 40 | return totalPrice; 41 | } 42 | 43 | public void logInformation(String message) { 44 | FileLogger fileLogger = new FileLogger(); 45 | ConsoleLogger consoleLogger = new ConsoleLogger(); 46 | 47 | fileLogger.logInFile(message); 48 | consoleLogger.logInConsole(message); 49 | } 50 | 51 | public class FileLogger { 52 | public void logInFile(String message) { 53 | System.out.println("File Log: " + message); 54 | } 55 | } 56 | 57 | public class ConsoleLogger { 58 | public void logInConsole(String message) { 59 | System.out.println("Console Log : " + message); 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/srp/violation/Item.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.srp.violation; 2 | 3 | public class Item { 4 | private String name; 5 | private Double price; 6 | 7 | public Item(String name, Double price) { 8 | this.name = name; 9 | this.price = price; 10 | } 11 | 12 | public String getName() { 13 | return name; 14 | } 15 | 16 | public void setName(String name) { 17 | this.name = name; 18 | } 19 | 20 | public Double getPrice() { 21 | return price; 22 | } 23 | 24 | public void setPrice(Double price) { 25 | this.price = price; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/techtong/solid/srp/violation/Main.java: -------------------------------------------------------------------------------- 1 | package com.techtong.solid.srp.violation; 2 | 3 | import java.util.List; 4 | 5 | public class Main { 6 | 7 | public static void main(String[] args) { 8 | Item cleanCodeBook = new Item("Clean Code", 100.0); 9 | Item mask = new Item("Mask", 10.0); 10 | Item tShirt = new Item("Mask", 20.0); 11 | 12 | int plasticBagTaken = 2; 13 | int tax = 10; 14 | 15 | var itemsPurchased = List.of(cleanCodeBook, mask, tShirt); 16 | 17 | Customer uncleBob = new Customer("Robert C Martin", 18 | 68, 19 | itemsPurchased, 20 | plasticBagTaken); 21 | 22 | double totalPriceOfItems = uncleBob.calculatePrice(tax); 23 | 24 | System.out.println("Total Prices of items purchased : " + totalPriceOfItems); 25 | 26 | } 27 | } 28 | --------------------------------------------------------------------------------