├── DesignPatterns ├── .gitignore ├── README.md ├── pom.xml └── src │ └── com │ └── tirthal │ └── learning │ └── design │ └── patterns │ ├── behavioral │ ├── README.md │ ├── observer │ │ ├── AppTestDrive.java │ │ ├── Auctioner.java │ │ ├── Bidder.java │ │ ├── DisplayElement.java │ │ ├── Observer.java │ │ ├── README.md │ │ └── Subject.java │ └── strategy │ │ ├── AppTestDrive.java │ │ ├── MakeMyTrip.java │ │ ├── Merchant.java │ │ ├── Myntra.java │ │ ├── PayByCash.java │ │ ├── PayByCreditCard.java │ │ ├── PayByPaypal.java │ │ ├── PaymentStrategy.java │ │ └── README.md │ ├── creational │ ├── README.md │ ├── abstractfactory │ │ ├── AmexFactory.java │ │ ├── AmexGoldCreditCard.java │ │ ├── AmexGoldValidator.java │ │ ├── AmexPlatinumCreditCard.java │ │ ├── AmexPlatinumValidator.java │ │ ├── AppTestDrive.java │ │ ├── CardType.java │ │ ├── CreditCard.java │ │ ├── CreditCardFactory.java │ │ ├── MasterCardFactory.java │ │ ├── MasterEliteCreditCard.java │ │ ├── MasterEliteValidator.java │ │ ├── MasterGoldCreditCard.java │ │ ├── MasterGoldValidator.java │ │ ├── README.md │ │ ├── Validator.java │ │ ├── VisaBlackCreditCard.java │ │ ├── VisaBlackValidator.java │ │ ├── VisaFactory.java │ │ ├── VisaGoldCreditCard.java │ │ └── VisaGoldValidator.java │ ├── builder │ │ ├── AppTestDrive.java │ │ ├── Person.java │ │ └── README.md │ ├── factorymethod │ │ ├── AppTestDrive.java │ │ ├── CashPayment.java │ │ ├── CreditCardPayment.java │ │ ├── NetbankingPayment.java │ │ ├── Payment.java │ │ ├── PaymentFactory.java │ │ ├── PaymentOptions.java │ │ └── README.md │ ├── objectpool │ │ └── README.md │ ├── prototype │ │ ├── AppTestDrive.java │ │ ├── Circle.java │ │ ├── README.md │ │ ├── Rectangle.java │ │ ├── Shape.java │ │ ├── ShapeRegistry.java │ │ └── Square.java │ └── singleton │ │ ├── AppTestDrive.java │ │ ├── LoggerUsingEagerInstantiation.java │ │ ├── LoggerUsingEnum.java │ │ ├── LoggerUsingInnerClass.java │ │ ├── LoggerUsingLazyInstantiationDoubleLocking.java │ │ └── README.md │ └── structural │ ├── README.md │ ├── adapter │ ├── AppTestDrive.java │ ├── CsvAdapterImpl.java │ ├── CsvFormattable.java │ ├── CsvFormatter.java │ ├── NewlineFormatter.java │ ├── README.md │ └── TextFormattable.java │ ├── bridge │ ├── AppTestDrive.java │ ├── Assemble.java │ ├── Bike.java │ ├── Car.java │ ├── Produce.java │ ├── README.md │ ├── Vehicle.java │ └── Workshop.java │ ├── composite │ ├── AppTestDrive.java │ ├── Menu.java │ ├── MenuComponent.java │ ├── MenuItem.java │ └── README.md │ └── decorator │ ├── AppTestDrive.java │ ├── Beverage.java │ ├── CondimentDecorator.java │ ├── Milk.java │ ├── README.md │ ├── RedTea.java │ ├── Sugar.java │ └── TeaMasala.java ├── DesignPrinciples ├── .gitignore ├── README.md ├── pom.xml └── src │ └── com │ └── tirthal │ └── learning │ └── oop │ ├── README.md │ ├── concepts │ ├── AggregationComposition_TestDrive.java │ ├── Cohesion_TestDrive.java │ ├── Delegation_InsteadOfGetterSetter_TestDrive.java │ ├── Delegation_TestDrive.java │ ├── Encapsulation_TestDrive.java │ ├── Inheritance_TestDrive.java │ ├── LooseCoupling_TestDrive.java │ ├── Polymorphism_TestDrive.java │ └── README.md │ └── design │ └── principles │ └── clazz │ └── solid │ ├── README.md │ ├── dip │ ├── README.md │ └── authentication │ │ ├── bad │ │ ├── LoginManager.java │ │ ├── SimpleAuthenticator.java │ │ └── User.java │ │ └── good │ │ ├── Authenticator.java │ │ ├── LDAPAuthenticator.java │ │ ├── LoginManager.java │ │ ├── SimpleAuthenticator.java │ │ └── User.java │ ├── isp │ ├── README.md │ └── order │ │ ├── bad │ │ ├── Order.java │ │ └── OrderService.java │ │ └── good │ │ ├── Order.java │ │ ├── OrderProcessingService.java │ │ └── OrderService.java │ ├── lsp │ ├── README.md │ └── mediaplayer │ │ ├── bad │ │ ├── ClientTestProgram.java │ │ ├── DivMediaPlayer.java │ │ ├── MediaPlayer.java │ │ ├── VideoUnsupportedException.java │ │ ├── VlcMediaPlayer.java │ │ └── WinampMediaPlayer.java │ │ └── good │ │ ├── AudioMediaPlayer.java │ │ ├── ClientTestProgram.java │ │ ├── DivMediaPlayer.java │ │ ├── MediaPlayer.java │ │ ├── VideoMediaPlayer.java │ │ ├── VideoUnsupportedException.java │ │ ├── VlcMediaPlayer.java │ │ └── WinampMediaPlayer.java │ ├── ocp │ ├── README.md │ ├── drawing │ │ ├── bad │ │ │ ├── Circle.java │ │ │ ├── GraphicEditor.java │ │ │ ├── GraphicEditorTestDrive.java │ │ │ ├── Rectangle.java │ │ │ └── Shape.java │ │ └── good │ │ │ ├── Circle.java │ │ │ ├── GraphicEditor.java │ │ │ ├── GraphicEditorTestDrive.java │ │ │ ├── Rectangle.java │ │ │ └── Shape.java │ ├── exporter │ │ ├── bad │ │ │ └── Order.java │ │ └── good │ │ │ ├── JsonExporter.java │ │ │ ├── JsonImporter.java │ │ │ ├── Order.java │ │ │ ├── XmlExporter.java │ │ │ └── XmlImporter.java │ └── parsing │ │ ├── bad │ │ └── FileParser.java │ │ └── good │ │ └── FileParser.java │ └── srp │ ├── README.md │ └── modem │ ├── bad │ ├── IModem.java │ ├── ModemFast.java │ ├── ModemFastClient.java │ ├── ModemSlow.java │ └── ModemSlowClient.java │ └── good │ ├── ConnectionManager.java │ ├── DataChannelFastMode.java │ ├── DataChannelSlowMode.java │ ├── IConnection.java │ ├── IDataChannel.java │ ├── Modem.java │ ├── ModemFastClient.java │ └── ModemSlowClient.java ├── LICENSE └── README.md /DesignPatterns/.gitignore: -------------------------------------------------------------------------------- 1 | /.settings/ 2 | /target/ 3 | /.classpath 4 | /.project 5 | -------------------------------------------------------------------------------- /DesignPatterns/README.md: -------------------------------------------------------------------------------- 1 | # Learn Design Patterns 2 | 3 | This project contains sample java code (by practical examples along with easy to understand comments) to learn design patterns. 4 | 5 | ## How to use this project? 6 | 7 | Just import this project in Eclipse as an "Existing Maven Project". If require, do necessary configuration to fix build path errors (e.g. setup JRE 1.8). 8 | 9 | ## Motive 10 | 11 | Lastly in year 2005, I read "Head First Design Patterns" book and then I consider patterns usage in coding as and when required. 12 | 13 | Again I thought to revise my design patterns knowledge in chunks by 2016 year, and this project would be consequence of it. 14 | 15 | I consider to take some content from below resources for the quick reference, so credit goes to authors of "Tutorials Point", "Java Point", "SourceMaking Site", "OODesign Site", "Design Patterns DZone Refcard" and "Design Patterns in Java courses of Pluralsight". 16 | 17 | * http://www.javatpoint.com/design-patterns-in-java 18 | * http://www.tutorialspoint.com/design_pattern/index.htm 19 | * http://sourcemaking.com/design_patterns 20 | * http://www.oodesign.com/ 21 | * http://refcardz.dzone.com/refcardz/design-patterns 22 | * https://app.pluralsight.com/library/search?q=%22Design+Patterns+in+Java%22 23 | 24 | Additionally, I intend to implement some of java code examples based on my experience. 25 | 26 | 27 | ## Design Patterns 28 | 29 | * are recurring solutions to software design problems you find again and again in real-world application development. 30 | * are just a description or template for how to solve a problem that can be used in many different situations, so can't be transformed directly into code. 31 | * can speed up the development process by providing tested, proven development paradigms. 32 | * allow developers to communicate using well-known, well understood names for software interactions. 33 | * allow you to get experience reuse, instead of code reuse. 34 | 35 | Patterns can be categorized under the following heads based on Scope. 36 | 37 | * Class - Deals with class relationships that can be changed at compile time. 38 | * Object - Deals with object relationships that can be changed at runtime. 39 | 40 | The design patterns in java are generally categorized as following. 41 | 42 | ## Creational Patterns 43 | 44 | Focuses on object instantiation or how objects are created. Let you construct objects such that they can be decoupled from their implementing system. [Start exploring creation patterns](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/creational), 45 | 46 | * [Singleton](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/singleton) 47 | * [Builder](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/builder) 48 | * [Prototype](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/prototype) 49 | * [Factory Method](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/factorymethod) 50 | * [Abstract Factory](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory) 51 | * [Object Pool](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/objectpool) 52 | 53 | ## Structural Patterns 54 | 55 | Focuses on the relationship of classes structure. Let you ease the design by identifying a simple way to realize relationships between entities. [Start exploring structural patterns](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/structural), 56 | 57 | * [Adapter](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/structural/adapter) 58 | * [Bridge](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/structural/bridge) 59 | * [Composite](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/structural/composite) 60 | * [Decorator](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/structural/decorator) 61 | * Facade 62 | * Flyweight 63 | * Proxy 64 | * Private Class Data 65 | 66 | ## Behavioral Patterns 67 | 68 | Focuses on the communication between objects. Let you manage algorithms, relationships, and responsibilities between objects. [Start exploring behavioral patterns](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral), 69 | 70 | * Chain of Responsibility 71 | * Command 72 | * Interpreter 73 | * Iterator 74 | * Mediator 75 | * Memento 76 | * Null Object 77 | * [Observer](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/observer) 78 | * State 79 | * [Strategy](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/strategy) 80 | * Template Method 81 | * Visitor 82 | 83 | ## Concurrency Patterns 84 | 85 | Let you deal with the multi-threaded programming paradigm. 86 | 87 | To be added in future 88 | 89 | 90 | 91 | ## Disclaimer 92 | 93 | The code snippet are mainly targeted for learning purpose, and not focused for producing production code quality. -------------------------------------------------------------------------------- /DesignPatterns/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | DesignPatterns 6 | DesignPatterns 7 | jar 8 | 0.0.1-SNAPSHOT 9 | Sample code snippet to learn design patterns 10 | 11 | 12 | src 13 | 14 | 15 | org.apache.maven.plugins 16 | maven-compiler-plugin 17 | 2.3.2 18 | 19 | 1.8 20 | 1.8 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/README.md: -------------------------------------------------------------------------------- 1 | # Behavioral Patterns 2 | 3 | * The behavioral patterns provide solution for the better interaction between objects and how to provide lose coupling and flexibility to extend easily. 4 | * The behavioral patterns are about communication between separate objects and they specify how separate objects interact. 5 | * The behavioral patterns describe the ways objects and classes interact and divide responsibilities among themselves. 6 | 7 | ## See it in Action: 8 | 9 | * Chain of Responsibility - A way of passing a request between a chain of objects 10 | * Command - Encapsulate a command request as an object 11 | * Interpreter - A way to include language elements in a program 12 | * Iterator - Sequentially access the elements of a collection 13 | * Mediator - Defines simplified communication between classes 14 | * Memento - Capture and restore an object's internal state 15 | * Null Object - Designed to act as a default value of an object 16 | * [Observer](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/observer) - A way of notifying change to a number of classes 17 | * State - Alter an object's behavior when its state changes 18 | * [Strategy](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/strategy) - Encapsulates an algorithm inside a class 19 | * Template Method - Defer the exact steps of an algorithm to a subclass 20 | * Visitor - Defines a new operation to a class without change -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/observer/AppTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.observer; 2 | 3 | import java.util.InputMismatchException; 4 | import java.util.Scanner; 5 | 6 | /** 7 | * Demo client which registers and unregister bidders (observers) with auctioner (subject) participate in the auction. If we see, client app is not 8 | * responsible to broadcast updates to all registered observers, rather it is accomplished through observer pattern. 9 | * 10 | * See implementation classes of Subject and Observer interfaces. 11 | * 12 | * @author tirthalp 13 | * 14 | */ 15 | public class AppTestDrive { 16 | 17 | public static void main(String[] args) { 18 | Auctioner auctioner = new Auctioner(); 19 | 20 | Bidder b1 = new Bidder("Bidder One - Kat"); 21 | Bidder b2 = new Bidder("Bidder Two - Ash"); 22 | Bidder b3 = new Bidder("Bidder Three - Jade"); 23 | 24 | // Register bidders 25 | System.out.println("------ Registering all bidders"); 26 | auctioner.registerObserver(b1); 27 | auctioner.registerObserver(b2); 28 | auctioner.registerObserver(b3); 29 | 30 | // Auctioner to broadcast bid price 31 | System.out.println("------ Enter 'C' to close the bid."); 32 | Scanner scan = new Scanner(System.in); 33 | boolean isBidClosed = false; 34 | do { 35 | if (auctioner.getBidPrice() <= 0) 36 | System.out.print("Enter a starting bid price: "); 37 | else 38 | System.out.print("Enter a new highest bid price: "); 39 | 40 | try { 41 | auctioner.setBidPrice(scan.nextInt()); 42 | } catch (InputMismatchException e) { 43 | System.out.println("------ This bid is CLOSED now."); 44 | isBidClosed = true; 45 | scan.close(); 46 | } 47 | } while (isBidClosed == false); 48 | 49 | // Unregister bidders 50 | System.out.println("------ Unregistering all bidders"); 51 | auctioner.removeObserver(b1); 52 | auctioner.removeObserver(b2); 53 | auctioner.removeObserver(b3); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/observer/Auctioner.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.observer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Auctioner is implementation of Subject, and offers functionality to register observers, notify state updates to registered observers and unregister 8 | * observers. 9 | * 10 | * @author tirthalp 11 | * 12 | */ 13 | public class Auctioner implements Subject { 14 | private List observers; 15 | private float bidPrice; 16 | 17 | public Auctioner() { 18 | observers = new ArrayList(); 19 | } 20 | 21 | // Register 22 | @Override 23 | public void registerObserver(Observer o) { 24 | observers.add(o); 25 | System.out.println("Registered: " + o.toString()); 26 | } 27 | 28 | // Unregister 29 | @Override 30 | public void removeObserver(Observer o) { 31 | int i = observers.indexOf(o); 32 | if (i >= 0) { 33 | observers.remove(i); 34 | } 35 | System.out.println("Unregistered: " + o.toString()); 36 | } 37 | 38 | // Notify state changes 39 | @Override 40 | public void notifyObservers() { 41 | for (int i = 0; i < observers.size(); i++) { 42 | Observer observer = observers.get(i); 43 | observer.update(bidPrice); 44 | } 45 | } 46 | 47 | private void bidPriceChanged() { 48 | notifyObservers(); 49 | } 50 | 51 | public void setBidPrice(float bidPrice) { 52 | this.bidPrice = bidPrice; 53 | bidPriceChanged(); 54 | } 55 | 56 | public float getBidPrice() { 57 | return bidPrice; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/observer/Bidder.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.observer; 2 | 3 | /** 4 | * Bidder implementation of Observer type 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class Bidder implements Observer, DisplayElement { 10 | 11 | private String name; 12 | 13 | public Bidder(String name) { 14 | this.name = name; 15 | } 16 | 17 | @Override 18 | public void update(float price) { 19 | // Bidder to propose new bid price in the auction 20 | float newPriceForBidding = Math.round(price + (Math.random() * 100) + (Math.random() * 100)); 21 | display(newPriceForBidding); 22 | } 23 | 24 | @Override 25 | public void display(float proposedNewBid) { 26 | System.out.println("Bid of " + this.toString() + " - " + proposedNewBid); 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return name; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/observer/DisplayElement.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.observer; 2 | 3 | public interface DisplayElement { 4 | public void display(float proposedNewBid); 5 | } -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/observer/Observer.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.observer; 2 | 3 | /** 4 | * Observer interface 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public interface Observer { 10 | public void update(float price); 11 | } 12 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/observer/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/observer/README.md -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/observer/Subject.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.observer; 2 | 3 | /** 4 | * Subject interface 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public interface Subject { 10 | public void registerObserver(Observer o); 11 | public void removeObserver(Observer o); 12 | public void notifyObservers(); 13 | } 14 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/strategy/AppTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.strategy; 2 | 3 | /** 4 | * Client app for the demo of strategy pattern implementation for Payment methods 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class AppTestDrive { 10 | 11 | public static void main(String[] args) { 12 | 13 | // Client makes use of an encapsulated family of algorithms for payment 14 | 15 | // OO principle - programming to an interface, not an implementation 16 | Merchant m = new MakeMyTrip(); 17 | m.pay(50); // By default it pays by cash 18 | m.setPaymentMode(new PayByPaypal()); // Change payment mode to Paypal 19 | m.pay(100); 20 | 21 | m = new Myntra(); 22 | m.setPaymentMode(new PayByCreditCard()); 23 | m.pay(1000); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/strategy/MakeMyTrip.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.strategy; 2 | 3 | public class MakeMyTrip extends Merchant { 4 | 5 | @Override 6 | protected void printMessage() { 7 | System.out.println("Your payment is successful. Thank you for booking tickets with MakeMyTrip.com and hope to see you again!!!"); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/strategy/Merchant.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.strategy; 2 | 3 | /** 4 | * The Merchant client make use of use of an encapsulated family of algorithms for payment using PaymentStrategy interface 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public abstract class Merchant { 10 | 11 | private PaymentStrategy paymentMode; 12 | 13 | // By default make payment mode by cash 14 | public Merchant() { 15 | paymentMode = new PayByCash(); 16 | } 17 | 18 | // Allow to set behavior dynamically 19 | public void setPaymentMode(PaymentStrategy paymentMode) { 20 | this.paymentMode = paymentMode; 21 | } 22 | 23 | // Delegate to the behavior class 24 | public void pay(int amount) { 25 | paymentMode.pay(amount); 26 | printMessage(); 27 | System.out.println("---"); 28 | } 29 | 30 | // Each merchant can display different message 31 | protected abstract void printMessage(); 32 | } 33 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/strategy/Myntra.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.strategy; 2 | 3 | public class Myntra extends Merchant { 4 | 5 | @Override 6 | protected void printMessage() { 7 | System.out.println("Your payment is successful. Thank you for shopping with Myntra.com and hope to see you again!!!"); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/strategy/PayByCash.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.strategy; 2 | 3 | /** 4 | * A concrete implementation of payment strategy algorithm for payment by cash 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class PayByCash implements PaymentStrategy { 10 | 11 | @Override 12 | public void pay(int amount) { 13 | System.out.println("Amount paid by cash = " + amount); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/strategy/PayByCreditCard.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.strategy; 2 | 3 | /** 4 | * A concrete implementation of payment strategy algorithm for payment by credit card 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class PayByCreditCard implements PaymentStrategy { 10 | 11 | @Override 12 | public void pay(int amount) { 13 | System.out.println("Amount paid by credit card = " + amount); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/strategy/PayByPaypal.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.strategy; 2 | 3 | /** 4 | * A concrete implementation of payment strategy algorithm for payment by Paypal 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class PayByPaypal implements PaymentStrategy { 10 | 11 | @Override 12 | public void pay(int amount) { 13 | System.out.println("Amount paid by paypal gateway = " + amount); 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/strategy/PaymentStrategy.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.behavioral.strategy; 2 | 3 | /** 4 | * The interface to specify the signature of an algorithm (i.e. a behavior) for the Payment Strategy 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public interface PaymentStrategy { 10 | 11 | public void pay(int amount); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/strategy/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPatterns/src/com/tirthal/learning/design/patterns/behavioral/strategy/README.md -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/README.md -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/AmexFactory.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class AmexFactory extends CreditCardFactory { 4 | 5 | @Override 6 | public CreditCard getCreditCard(CardType cardType) { 7 | 8 | switch (cardType) { 9 | case GOLD: 10 | return new AmexGoldCreditCard(); 11 | case PLATINUM: 12 | return new AmexPlatinumCreditCard(); 13 | } 14 | 15 | return null; 16 | } 17 | 18 | @Override 19 | public Validator getValidator(CardType cardType) { 20 | 21 | switch (cardType) { 22 | case GOLD: 23 | return new AmexGoldValidator(); 24 | case PLATINUM: 25 | return new AmexPlatinumValidator(); 26 | } 27 | 28 | return null; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/AmexGoldCreditCard.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class AmexGoldCreditCard extends CreditCard { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/AmexGoldValidator.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class AmexGoldValidator implements Validator { 4 | 5 | @Override 6 | public boolean isValid(CreditCard cc) { 7 | 8 | // credit card validation logic ... 9 | 10 | return false; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/AmexPlatinumCreditCard.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class AmexPlatinumCreditCard extends CreditCard { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/AmexPlatinumValidator.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class AmexPlatinumValidator implements Validator { 4 | 5 | @Override 6 | public boolean isValid(CreditCard cc) { 7 | 8 | // credit card validation logic ... 9 | 10 | return false; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/AppTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | /** 4 | * Client app accessing example abstract factory pattern implementation 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class AppTestDrive { 10 | 11 | public static void main(String[] args) { 12 | 13 | CreditCardFactory abstractFactory = CreditCardFactory.getCreditCardFactory(900); 14 | 15 | CreditCard card1 = abstractFactory.getCreditCard(CardType.PLATINUM); 16 | System.out.println(card1); 17 | 18 | System.out.println("------------------"); 19 | 20 | abstractFactory = CreditCardFactory.getCreditCardFactory(450); 21 | 22 | CreditCard card2 = abstractFactory.getCreditCard(CardType.GOLD); 23 | System.out.println(card2); 24 | 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/CardType.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public enum CardType { 4 | 5 | GOLD, PLATINUM; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/CreditCard.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public abstract class CreditCard { 4 | 5 | protected int cardNumberLength; 6 | 7 | protected int cscNumber; 8 | 9 | public int getCardNumberLength() { 10 | return cardNumberLength; 11 | } 12 | 13 | public void setCardNumberLength(int cardNumberLength) { 14 | this.cardNumberLength = cardNumberLength; 15 | } 16 | 17 | public int getCscNumber() { 18 | return cscNumber; 19 | } 20 | 21 | public void setCscNumber(int cscNumber) { 22 | this.cscNumber = cscNumber; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/CreditCardFactory.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | /** 4 | * Example of Abstract Factory 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public abstract class CreditCardFactory { 10 | 11 | public static CreditCardFactory getCreditCardFactory(int creditScore) { 12 | 13 | if(creditScore > 750) { 14 | return new AmexFactory(); 15 | } 16 | else if(creditScore <= 750 && creditScore >= 500) { 17 | return new MasterCardFactory(); 18 | } 19 | else { 20 | return new VisaFactory(); 21 | } 22 | 23 | } 24 | 25 | public abstract CreditCard getCreditCard(CardType cardType); 26 | 27 | public abstract Validator getValidator(CardType cardType); 28 | } 29 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/MasterCardFactory.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class MasterCardFactory extends CreditCardFactory { 4 | 5 | @Override 6 | public CreditCard getCreditCard(CardType cardType) { 7 | 8 | switch (cardType) { 9 | case GOLD: 10 | return new MasterGoldCreditCard(); 11 | case PLATINUM: 12 | return new MasterEliteCreditCard(); 13 | } 14 | 15 | return null; 16 | } 17 | 18 | @Override 19 | public Validator getValidator(CardType cardType) { 20 | 21 | switch (cardType) { 22 | case GOLD: 23 | return new MasterGoldValidator(); 24 | case PLATINUM: 25 | return new MasterEliteValidator(); 26 | } 27 | 28 | return null; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/MasterEliteCreditCard.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class MasterEliteCreditCard extends CreditCard { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/MasterEliteValidator.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class MasterEliteValidator implements Validator { 4 | 5 | @Override 6 | public boolean isValid(CreditCard cc) { 7 | 8 | // credit card validation logic ... 9 | 10 | return false; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/MasterGoldCreditCard.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class MasterGoldCreditCard extends CreditCard { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/MasterGoldValidator.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class MasterGoldValidator implements Validator { 4 | 5 | @Override 6 | public boolean isValid(CreditCard cc) { 7 | 8 | // credit card validation logic ... 9 | 10 | return false; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/README.md -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/Validator.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public interface Validator { 4 | 5 | public boolean isValid(CreditCard cc); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/VisaBlackCreditCard.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class VisaBlackCreditCard extends CreditCard { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/VisaBlackValidator.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class VisaBlackValidator implements Validator { 4 | 5 | @Override 6 | public boolean isValid(CreditCard cc) { 7 | 8 | // credit card validation logic ... 9 | 10 | return false; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/VisaFactory.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class VisaFactory extends CreditCardFactory { 4 | 5 | @Override 6 | public CreditCard getCreditCard(CardType cardType) { 7 | 8 | switch (cardType) { 9 | case GOLD: 10 | return new VisaGoldCreditCard(); 11 | case PLATINUM: 12 | return new VisaBlackCreditCard(); 13 | } 14 | 15 | return null; 16 | } 17 | 18 | @Override 19 | public Validator getValidator(CardType cardType) { 20 | 21 | switch (cardType) { 22 | case GOLD: 23 | return new VisaGoldValidator(); 24 | case PLATINUM: 25 | return new VisaBlackValidator(); 26 | } 27 | 28 | return null; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/VisaGoldCreditCard.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class VisaGoldCreditCard extends CreditCard { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/abstractfactory/VisaGoldValidator.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.abstractfactory; 2 | 3 | public class VisaGoldValidator implements Validator { 4 | 5 | @Override 6 | public boolean isValid(CreditCard cc) { 7 | 8 | // credit card validation logic ... 9 | 10 | return false; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/builder/AppTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.builder; 2 | 3 | /** 4 | * Client app accessing different implementations of builder pattern examples 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class AppTestDrive { 10 | 11 | public static void main(String[] args) { 12 | 13 | // --- Real world example - Java StringBuilder 14 | StringBuilder sb = new StringBuilder().append("This is an example ") 15 | .append("of the builder pattern. "); 16 | sb.insert(sb.length(), "Awesome!"); 17 | System.out.println(sb.toString()); 18 | System.out.println("-------------"); 19 | 20 | // --- Custom builder example of Person 21 | Person person = new Person.Builder().firstName("Tirthal") 22 | .lastName("Patel") 23 | .middleName("D") 24 | .salutation("Mr.") 25 | .age(30) 26 | .build(); 27 | 28 | System.out.println(person.getFirstName()); 29 | System.out.println(person); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/builder/Person.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.builder; 2 | 3 | /** 4 | * Example code snippet of builder pattern implementation - nested Person.Builder 5 | * 6 | * @author tirthalp 7 | */ 8 | public class Person { 9 | 10 | // Nested Person.Builder 11 | 12 | public static class Builder { 13 | 14 | private String lastName; 15 | private String firstName; 16 | private String middleName; 17 | private String salutation; 18 | private int age; 19 | 20 | // Build immutable object 21 | public Person build() { 22 | return new Person(this); 23 | } 24 | 25 | public Builder lastName(String lastName) { 26 | this.lastName = lastName; 27 | return this; 28 | } 29 | 30 | public Builder firstName(String firstName) { 31 | this.firstName = firstName; 32 | return this; 33 | } 34 | 35 | public Builder middleName(String middleName) { 36 | this.middleName = middleName; 37 | return this; 38 | } 39 | 40 | public Builder salutation(String salutation) { 41 | this.salutation = salutation; 42 | return this; 43 | } 44 | 45 | public Builder age(int age) { 46 | this.age = age; 47 | return this; 48 | } 49 | } 50 | 51 | // Person attributes, constructor and getter methods 52 | 53 | private final String lastName; 54 | private final String firstName; 55 | private final String middleName; 56 | private final String salutation; 57 | private final int age; 58 | 59 | // private constructor, because only internal builder needs to call me to provide my instance to clients 60 | private Person(Builder builder) { 61 | this.firstName = builder.firstName; 62 | this.lastName = builder.lastName; 63 | this.middleName = builder.middleName; 64 | this.salutation = builder.salutation; 65 | this.age = builder.age; 66 | } 67 | 68 | // No setters, rather having only getters 69 | public String getLastName() { 70 | return lastName; 71 | } 72 | public String getFirstName() { 73 | return firstName; 74 | } 75 | public String getMiddleName() { 76 | return middleName; 77 | } 78 | public String getSalutation() { 79 | return salutation; 80 | } 81 | public int getAge() { 82 | return age; 83 | } 84 | 85 | @Override 86 | public int hashCode() { 87 | final int prime = 31; 88 | int result = 1; 89 | result = prime * result + age; 90 | result = prime * result + ((firstName == null) ? 0 : firstName.hashCode()); 91 | result = prime * result + ((lastName == null) ? 0 : lastName.hashCode()); 92 | result = prime * result + ((middleName == null) ? 0 : middleName.hashCode()); 93 | result = prime * result + ((salutation == null) ? 0 : salutation.hashCode()); 94 | return result; 95 | } 96 | 97 | @Override 98 | public boolean equals(Object obj) { 99 | if (this == obj) 100 | return true; 101 | if (obj == null) 102 | return false; 103 | if (getClass() != obj.getClass()) 104 | return false; 105 | Person other = (Person) obj; 106 | if (age != other.age) 107 | return false; 108 | if (firstName == null) { 109 | if (other.firstName != null) 110 | return false; 111 | } else if (!firstName.equals(other.firstName)) 112 | return false; 113 | if (lastName == null) { 114 | if (other.lastName != null) 115 | return false; 116 | } else if (!lastName.equals(other.lastName)) 117 | return false; 118 | if (middleName == null) { 119 | if (other.middleName != null) 120 | return false; 121 | } else if (!middleName.equals(other.middleName)) 122 | return false; 123 | if (salutation == null) { 124 | if (other.salutation != null) 125 | return false; 126 | } else if (!salutation.equals(other.salutation)) 127 | return false; 128 | return true; 129 | } 130 | 131 | @Override 132 | public String toString() { 133 | return "Person [lastName=" + lastName + ", firstName=" + firstName + ", middleName=" + middleName 134 | + ", salutation=" + salutation + ", age=" + age + "]"; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/builder/README.md: -------------------------------------------------------------------------------- 1 | # Builder Pattern 2 | 3 | To simplify complex object creation by defining a class whose purpose is to build instances of another class. The Builder produces one main product, such that there might be more than one class in the product, but there is always one main class. 4 | 5 | ## Usage / Concepts 6 | 7 | * To handles complex constructors (i.e. to find a solution to the telescoping constructor anti-pattern) or large number of parameters. 8 | * Can force immutability on object, once construction is finished. 9 | * Object creation algorithms should be decoupled from the system. 10 | * Multiple representations of creation algorithms are required. 11 | * Runtime control over steps of construction process is required. 12 | * Offers a client object to construct a complex object by specifying only its type and content, being shielded from the details related to the object's representation. 13 | 14 | ## See it in Action / Sample Code Snippet 15 | 16 | * Java StringBuilder and custom Person class - Creating immutable object using builder approach. 17 | * Run [AppTestDrive.java](https://github.com/tirthalpatel/Learning-OOPD/blob/master/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/builder/AppTestDrive.java) and refer the corresponding code flow. 18 | 19 | ## Key Design Considerations 20 | 21 | * Flexibility over telescoping constructors. 22 | * Static inner builder class - builds immutable object and negates the need for exposed setters. 23 | * Private constructor of class, which is called by internal builder to provide class instance to clients. 24 | 25 | ## Hot Spots 26 | 27 | * Builder approach essentially doubles the number of lines of code for each attribute, however, client code benefits greatly in terms of usability and readability. 28 | * Lack of IDE support - Majority Java IDE supporting code generation for constructors and setters, however, lacking similar support for builder implementation. 29 | 30 | ## Real World Examples 31 | 32 | * [java.util.Locale.Builder](https://docs.oracle.com/javase/7/docs/api/java/util/Locale.Builder.html) 33 | * [java.lang.StringBuilder](https://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html) 34 | * [java.nio.ByteBuffer#put()](https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#put(byte)) 35 | * [javax.xml.parsers.DocumentBuilder](https://docs.oracle.com/javase/7/docs/api/javax/xml/parsers/DocumentBuilder.html) 36 | * [Lombok's Builder](https://projectlombok.org/features/Builder.html) -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/factorymethod/AppTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.factorymethod; 2 | 3 | import java.util.Calendar; 4 | 5 | /** 6 | * Client app accessing example factory method pattern implementation 7 | * 8 | * @author tirthalp 9 | * 10 | */ 11 | public class AppTestDrive { 12 | 13 | public static void main(String[] args) { 14 | 15 | // --- Real world example - Java Calendar 16 | Calendar cal = Calendar.getInstance(); 17 | System.out.println(cal); 18 | System.out.println("-----------------------------"); 19 | 20 | // --- Custom factory method example for Payment use case 21 | Payment p = PaymentFactory.getInstance(); 22 | p.pay(); 23 | 24 | p = PaymentFactory.getInstance(PaymentOptions.NET_BANKING); 25 | p.pay(); 26 | 27 | p = PaymentFactory.getInstance(PaymentOptions.CREDIT_CARD); 28 | p.pay(); 29 | 30 | p = PaymentFactory.getInstance(PaymentOptions.CASH); 31 | p.pay(); 32 | 33 | // Awesome: Factory method promotes the loose-coupling by hiding object instantiation logic from client code 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/factorymethod/CashPayment.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.factorymethod; 2 | 3 | /** 4 | * Concrete implementation of Payment interface 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class CashPayment implements Payment { 10 | 11 | @Override 12 | public void pay() { 13 | System.out.println("This is cash payment"); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/factorymethod/CreditCardPayment.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.factorymethod; 2 | 3 | /** 4 | * Concrete implementation of Payment interface 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class CreditCardPayment implements Payment { 10 | 11 | @Override 12 | public void pay() { 13 | System.out.println("This is credit card payment"); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/factorymethod/NetbankingPayment.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.factorymethod; 2 | 3 | /** 4 | * Concrete implementation of Payment interface 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class NetbankingPayment implements Payment { 10 | 11 | @Override 12 | public void pay() { 13 | System.out.println("This is net banking payment"); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/factorymethod/Payment.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.factorymethod; 2 | 3 | /** 4 | * The Payment interface for objects the factory method creates 5 | * 6 | * @author tirthalp 7 | */ 8 | public interface Payment { 9 | 10 | public void pay(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/factorymethod/PaymentFactory.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.factorymethod; 2 | 3 | /** 4 | * Example implementation of Factory method pattern 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class PaymentFactory { 10 | 11 | // Factory methods to return payment instance type 12 | public static Payment getInstance(PaymentOptions option) { 13 | return createPaymentType(option); 14 | } 15 | 16 | public static Payment getInstance() { 17 | return createPaymentType(null); 18 | } 19 | 20 | // Object instantiation logic 21 | private static Payment createPaymentType(PaymentOptions option) { 22 | if(option==null) 23 | return new CashPayment(); // default payment option 24 | 25 | switch(option) { 26 | case CASH: 27 | return new CashPayment(); 28 | case CREDIT_CARD: 29 | return new CreditCardPayment(); 30 | case NET_BANKING: 31 | return new NetbankingPayment(); 32 | default: 33 | return new CashPayment(); // default payment option 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/factorymethod/PaymentOptions.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.factorymethod; 2 | 3 | /** 4 | * Constants for payment options 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public enum PaymentOptions { 10 | CASH, CREDIT_CARD, NET_BANKING; 11 | } 12 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/factorymethod/README.md: -------------------------------------------------------------------------------- 1 | # Factory Method Pattern 2 | 3 | To replace class constructors and abstract the process of object generation so that the type of the object instantiated can be determined at run-time. 4 | 5 | ## Usage / Concepts 6 | 7 | * Define a "virtual" constructor. Used to instantiate an object from one among a set of classes based on a logic. 8 | * Create object without exposing the creation logic to the client and refer to newly created object using a common interface. 9 | * Object instantiation logic should not be exposed to client. A client class will not know what classes it will be required to create. 10 | 11 | ## See it in Action / Sample Code Snippet 12 | 13 | * Factory method of Java Calendar and custom implementation of Payment use case. 14 | * Run [AppTestDrive.java](https://github.com/tirthalpatel/Learning-OOPD/blob/master/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/factorymethod/AppTestDrive.java) and refer the corresponding code flow. 15 | * Payment (interface) can have concrete implementations such as CashPayment, CreditCardPayment and NetbankingPayment. 16 | * PaymentFactory's factory method is responsible for creating instance of Payment as per supplied PaymentOption argument by client app. 17 | 18 | ## Key Design Considerations 19 | 20 | * Factory is responsible for object instantiation lifecycle. If applicable, consider designing an internal "object pool" that will allow objects to be reused instead of created from scratch. 21 | * Parameterized factory method - design the arguments to the factory method. What qualities or characteristics are necessary and sufficient to identify the correct derived class to instantiate? 22 | * If having an inheritance hierarchy that exercises polymorphism, consider adding a polymorphic creation capability by defining a static factory method in the base class. 23 | 24 | ## Real World Examples 25 | 26 | * [java.util.Calendar#getInstace()](https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#getInstance()) 27 | * [java.util.ResourceBundle#getBundle()](https://docs.oracle.com/javase/7/docs/api/java/util/ResourceBundle.html#getBundle(java.lang.String)) 28 | * [java.text.NumberFormat#getInstance()](https://docs.oracle.com/javase/7/docs/api/java/text/NumberFormat.html#getInstance()) -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/objectpool/README.md: -------------------------------------------------------------------------------- 1 | # Object Pool Pattern 2 | 3 | To reuse the object that are expensive to create. Although the object pool is handling the object instantiation, it's main purpose is to provide a way for the clients to reuse the objects like they are new objects, without being shared. 4 | 5 | ## Usage / Concepts 6 | 7 | * When an application requires objects which are expensive to create. For example, there is a need of opening too many connections for the database then it takes too longer to create a new one and the database server will be overloaded. 8 | * When there are several clients who need the same resource at different times. 9 | 10 | ## See it in Action / Sample Code Snippet 11 | 12 | * [Creating Object Pool using Apache Commons Pool](https://dzone.com/articles/creating-object-pool-java) 13 | 14 | ## Key Design Considerations 15 | 16 | * An Object pool is a container which contains a specified amount of objects. When an object is taken from the pool, it is not available in the pool until it is put back. 17 | * Objects in the pool have a lifecycle: creation, validation and destroy. 18 | 19 | ## Hot Spots 20 | 21 | * When the Object Pool pattern is used the objects should be marked as available(released) by the client after they are used, so the pool will be aware about this. This is the main drawback because the client should do this and it's a common situation when database connection are not released after they are used. To overcome this a mechanism can be implemented to release resources, if they are not used for a period of time. 22 | * Creating the resources might fail and this case should be treated carefully. When there is no available resource (because the number is limited or creating a new one failed) the client should be notified about it. 23 | 24 | ## Real World Examples 25 | 26 | * Java supports thread pooling via java.util.concurrent.ExecutorService and other related classes 27 | * The data source pools and thread pools in application servers -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/prototype/AppTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.prototype; 2 | 3 | /** 4 | * Client app accessing implementations of prototype pattern example 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class AppTestDrive { 10 | 11 | public static void main(String[] args) { 12 | 13 | // Although a cloned copy, each instance is unique 14 | 15 | Shape clonedShape1 = (Shape) ShapeRegistry.getShape("1"); 16 | System.out.println("Shape : " + clonedShape1); 17 | 18 | clonedShape1 = (Shape) ShapeRegistry.getShape("1"); 19 | System.out.println("Shape : " + clonedShape1); 20 | 21 | clonedShape1 = (Shape) ShapeRegistry.getShape("1"); 22 | System.out.println("Shape : " + clonedShape1); 23 | 24 | System.out.println("-----------"); 25 | 26 | Shape clonedShape2 = (Shape) ShapeRegistry.getShape("2"); 27 | System.out.println("Shape : " + clonedShape2); 28 | 29 | clonedShape2 = (Shape) ShapeRegistry.getShape("2"); 30 | System.out.println("Shape : " + clonedShape2); 31 | 32 | System.out.println("-----------"); 33 | 34 | Shape clonedShape3 = (Shape) ShapeRegistry.getShape("3"); 35 | System.out.println("Shape : " + clonedShape3); 36 | 37 | clonedShape3 = (Shape) ShapeRegistry.getShape("3"); 38 | System.out.println("Shape : " + clonedShape3); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/prototype/Circle.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.prototype; 2 | 3 | public class Circle extends Shape { 4 | 5 | public Circle() { 6 | type = "Circle"; 7 | } 8 | 9 | @Override 10 | public void draw() { 11 | System.out.println("Inside Circle::draw() method."); 12 | } 13 | } -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/prototype/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/prototype/README.md -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/prototype/Rectangle.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.prototype; 2 | 3 | public class Rectangle extends Shape { 4 | 5 | public Rectangle() { 6 | type = "Rectangle"; 7 | } 8 | 9 | @Override 10 | public void draw() { 11 | System.out.println("Inside Rectangle::draw() method."); 12 | } 13 | } -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/prototype/Shape.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.prototype; 2 | 3 | // An abstract class implementing Clonable interface 4 | public abstract class Shape implements Cloneable { 5 | 6 | private String id; 7 | protected String type; 8 | 9 | abstract void draw(); 10 | 11 | public String getType() { 12 | return type; 13 | } 14 | 15 | public String getId() { 16 | return id; 17 | } 18 | 19 | public void setId(String id) { 20 | this.id = id; 21 | } 22 | 23 | public Object clone() { 24 | Object clone = null; 25 | 26 | try { 27 | clone = super.clone(); 28 | 29 | } catch (CloneNotSupportedException e) { 30 | e.printStackTrace(); 31 | } 32 | 33 | return clone; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return super.toString() + " [id=" + id + ", type=" + type + "]"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/prototype/ShapeRegistry.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.prototype; 2 | 3 | import java.util.Hashtable; 4 | 5 | /** 6 | * A registry / cache, which avoids costly object creation and provides cloned object 7 | * 8 | * @author tirthalp 9 | */ 10 | public class ShapeRegistry { 11 | 12 | private static Hashtable shapesCache = new Hashtable(); 13 | 14 | static { 15 | loadShapes(); 16 | } 17 | 18 | public static Shape getShape(String shapeId) { 19 | Shape cachedShape = shapesCache.get(shapeId); 20 | 21 | // Typically avoid usage of "new". Rather returns unique instance as a cloned copy. 22 | return (Shape) cachedShape.clone(); 23 | } 24 | 25 | /* 26 | * Assume, initial creation of each object is an expensive operation here. May be for each shape, it needs to run 27 | * database query. 28 | * 29 | * So instead of triggering that process every time, better to cache them using shapesCache.put(shapeKey, shape). 30 | */ 31 | private static void loadShapes() { 32 | Circle circle = new Circle(); 33 | circle.setId("1"); 34 | shapesCache.put(circle.getId(), circle); 35 | 36 | Square square = new Square(); 37 | square.setId("2"); 38 | shapesCache.put(square.getId(), square); 39 | 40 | Rectangle rectangle = new Rectangle(); 41 | rectangle.setId("3"); 42 | shapesCache.put(rectangle.getId(), rectangle); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/prototype/Square.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.prototype; 2 | 3 | public class Square extends Shape { 4 | 5 | public Square() { 6 | type = "Square"; 7 | } 8 | 9 | @Override 10 | public void draw() { 11 | System.out.println("Inside Square::draw() method."); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/singleton/AppTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.singleton; 2 | 3 | /** 4 | * Client app accessing different implementations of singleton pattern for Logger example 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class AppTestDrive { 10 | 11 | public static void main(String[] args) { 12 | 13 | // --- Real world example - Java Runtime 14 | Runtime r1 = Runtime.getRuntime(); 15 | Runtime r2 = Runtime.getRuntime(); 16 | System.out.println(r1); 17 | System.out.println(r2); 18 | if(r1 == r2) 19 | System.out.println("'" + r1 + "' and '" + r2 + "' both are same."); 20 | System.out.println("-------------"); 21 | 22 | // --- Custom singleton Logger instances 23 | 24 | // Option 1 - eager instantiation 25 | LoggerUsingEagerInstantiation.getInstance().print(); 26 | LoggerUsingEagerInstantiation.getInstance().print(); 27 | LoggerUsingEagerInstantiation.getInstance().print(); 28 | LoggerUsingEagerInstantiation instance1 = LoggerUsingEagerInstantiation.getInstance(); 29 | LoggerUsingEagerInstantiation instance2 = LoggerUsingEagerInstantiation.getInstance(); 30 | if(instance1 == instance2) 31 | System.out.println("'" + instance1 + "' and '" + instance2 + "' both are same."); 32 | System.out.println("-------------"); 33 | 34 | // Option 2 - lazy instantiation using double locking mechanism 35 | LoggerUsingLazyInstantiationDoubleLocking.getInstance().print(); 36 | LoggerUsingLazyInstantiationDoubleLocking.getInstance().print(); 37 | LoggerUsingLazyInstantiationDoubleLocking.getInstance().print(); 38 | System.out.println("-------------"); 39 | 40 | // Option 3 - simplify singleton implementation using inner class 41 | LoggerUsingInnerClass.getInstance().print(); 42 | LoggerUsingInnerClass.getInstance().print(); 43 | LoggerUsingInnerClass.getInstance().print(); 44 | System.out.println("-------------"); 45 | 46 | // Option 4 - singleton implementation using Java 5 enum 47 | LoggerUsingEnum.getInstance().print(); 48 | LoggerUsingEnum.getInstance().print(); 49 | LoggerUsingEnum.getInstance().print(); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/singleton/LoggerUsingEagerInstantiation.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.singleton; 2 | 3 | /** 4 | * Example code snippet of Logger class singleton pattern implementation for eager instantiation. 5 | * 6 | * @author tirthalp 7 | */ 8 | public class LoggerUsingEagerInstantiation { 9 | 10 | private final static LoggerUsingEagerInstantiation m_instance = new LoggerUsingEagerInstantiation(); 11 | 12 | // Private constructor prevents instantiation from other classes 13 | private LoggerUsingEagerInstantiation() { 14 | System.out.println("LoggerUsingEagerInstantiation(): Initializing Instance"); 15 | } 16 | 17 | public static LoggerUsingEagerInstantiation getInstance() { 18 | return m_instance; 19 | } 20 | 21 | public void print() { 22 | System.out.println("Printing performed by object " + this); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/singleton/LoggerUsingEnum.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/singleton/LoggerUsingEnum.java -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/singleton/LoggerUsingInnerClass.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.singleton; 2 | 3 | /** 4 | * Example code snippet of Logger class singleton pattern implementation using inner class approach. 5 | * 6 | * @author tirthalp 7 | */ 8 | public class LoggerUsingInnerClass { 9 | 10 | // Private constructor prevents instantiation from other classes 11 | private LoggerUsingInnerClass() { 12 | System.out.println("LoggerUsingInnerClass(): Initializing Instance"); 13 | } 14 | 15 | /* 16 | * The inner class is referenced no earlier (and therefore loaded no earlier by the class loader) than the moment that getInstance() is called. 17 | * Thus, this solution is thread-safe without requiring special language constructs (i.e. volatile or synchronized). 18 | * 19 | * To sum up, LoggerHolder is loaded on the first execution of LoggerUsingInnerClass.getInstance() or the first access to LoggerHolder.INSTANCE, 20 | * not before. 21 | */ 22 | private static class LoggerHolder { 23 | private static final LoggerUsingInnerClass INSTANCE = new LoggerUsingInnerClass(); 24 | } 25 | 26 | public static LoggerUsingInnerClass getInstance() { 27 | return LoggerHolder.INSTANCE; 28 | } 29 | 30 | public void print() { 31 | System.out.println("Printing performed by object " + this); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/singleton/LoggerUsingLazyInstantiationDoubleLocking.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.creational.singleton; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Example code snippet of Logger class singleton pattern implementation for lazy instantiation using double locking mechanism. 7 | * 8 | * @author tirthalp 9 | */ 10 | public class LoggerUsingLazyInstantiationDoubleLocking implements Serializable { 11 | private static final long serialVersionUID = 1L; 12 | private static LoggerUsingLazyInstantiationDoubleLocking m_instance; 13 | 14 | // Private constructor prevents instantiation from other classes 15 | private LoggerUsingLazyInstantiationDoubleLocking() { 16 | System.out.println("LoggerUsingLazyInstantiationDoubleLocking(): Initializing Instance"); 17 | } 18 | 19 | /* 20 | * The singleton instance is created when the getInstance() method is called for the first time. This is called lazy instantiation and it ensures 21 | * that the singleton instance is created only when it is needed. 22 | */ 23 | public static LoggerUsingLazyInstantiationDoubleLocking getInstance() { 24 | if (m_instance == null) { 25 | synchronized (LoggerUsingLazyInstantiationDoubleLocking.class) { 26 | if (m_instance == null) { 27 | System.out.println("getInstance(): First time getInstance was invoked!"); 28 | m_instance = new LoggerUsingLazyInstantiationDoubleLocking(); 29 | } 30 | } 31 | } 32 | 33 | return m_instance; 34 | } 35 | 36 | /* 37 | * When Singletons are implementing Serializable interface they have to implement readResolve method in order to avoid having 2 different objects. 38 | * This method is called immediately after an object of this class is deserialized. This method returns the singleton instance. 39 | */ 40 | protected Object readResolve() { 41 | return getInstance(); 42 | } 43 | 44 | public void print() { 45 | System.out.println("Printing performed by object " + this); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/creational/singleton/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPatterns/src/com/tirthal/learning/design/patterns/creational/singleton/README.md -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPatterns/src/com/tirthal/learning/design/patterns/structural/README.md -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/adapter/AppTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.adapter; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | /** 7 | * Client app for demo of adapter pattern 8 | * 9 | * @author tirthalp 10 | * 11 | */ 12 | public class AppTestDrive { 13 | 14 | public static void main(String args[]) { 15 | 16 | // --- Real world example - Arrays.asList : convert Arrays -> List 17 | String[] colorsArray = new String[]{"red", "blue", "white", "black"}; 18 | List colorsList = Arrays.asList(colorsArray); 19 | System.out.println(colorsArray + " -> " + colorsList); 20 | System.out.println("---------------------------"); 21 | 22 | // --- Custom Adapter pattern example 23 | String input = "Hello world 1. Hello world 2. Hello world 3. Hello world 4. Hello world 5. "; 24 | 25 | TextFormattable tf = new NewlineFormatter(); 26 | System.out.println(tf.formatText(input, ". ")); 27 | 28 | // tf = new CsvFormatter(); // Obviously incompatible interface, so need adaptor 29 | tf = new CsvAdapterImpl(new CsvFormatter()); 30 | System.out.println(tf.formatText(input, ".")); 31 | 32 | // Likewise, there could be multiple adaptors as per need 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/adapter/CsvAdapterImpl.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.adapter; 2 | 3 | /** 4 | * An example adapter class that adapts the Adaptee to the Target 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class CsvAdapterImpl implements TextFormattable { 10 | 11 | private CsvFormatter cf; 12 | 13 | public CsvAdapterImpl(CsvFormatter cf) { 14 | this.cf = cf; 15 | } 16 | 17 | @Override 18 | public String formatText(String text, String separator) { 19 | 20 | return cf.formatCsvText(text, separator); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/adapter/CsvFormattable.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.adapter; 2 | 3 | /** 4 | * An example of incompatible interface that needs adapting 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public interface CsvFormattable { 10 | 11 | String formatCsvText(String text, String separator); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/adapter/CsvFormatter.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.adapter; 2 | 3 | public class CsvFormatter implements CsvFormattable { 4 | 5 | @Override 6 | public String formatCsvText(String text, String separator) { 7 | 8 | if (text != null && separator != null) 9 | return text.replace(separator, ","); 10 | 11 | return null; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/adapter/NewlineFormatter.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.adapter; 2 | 3 | public class NewlineFormatter implements TextFormattable { 4 | 5 | @Override 6 | public String formatText(String text, String separator) { 7 | 8 | if (text != null && separator != null) 9 | return text.replace(separator, "\n"); 10 | 11 | return null; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/adapter/README.md: -------------------------------------------------------------------------------- 1 | # Adapter Pattern 2 | 3 | To act as an intermediary between two classes, converting the interface of one class so that it can be used with the other. Often designed to integrate new client with old/legacy components. 4 | 5 | ## Usage / Concepts 6 | 7 | * Use when an object needs to utilize an existing class with an incompatible interface. 8 | * Permits classes with disparate interfaces to work together by creating a common object by which they may communicate and interact. 9 | * Convert interface into another interface - for making things working after code is designed or specifically dealing with legacy code. 10 | * Retrofit to make unrelated classes work together or translate requests. 11 | 12 | ## See it in Action / Sample Code Snippet 13 | 14 | * Java Arrays.asList and custom adapter pattern example. 15 | * Run [AppTestDrive.java](https://github.com/tirthalpatel/Learning-OOPD/blob/master/DesignPatterns/src/com/tirthal/learning/design/patterns/structural/adapter/AppTestDrive.java) client and refer the corresponding code flow. 16 | * TextFormattable: Target 17 | * CsvFormattable: Adaptee 18 | * CsvAdapterImpl: Adapter 19 | 20 | ## Key Design Considerations 21 | 22 | Adapter makes things work after they're designed. The classes/objects participating in adapter pattern: 23 | 24 | * Target: defines the domain-specific interface that Client uses. 25 | * Adapter: adapts the interface Adaptee to the Target interface. 26 | * Adaptee: defines an existing interface that needs adapting. 27 | * Client: collaborates with objects conforming to the Target interface. 28 | 29 | ## Real World Examples 30 | 31 | * [Arrays -> List](https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#asList(T...)) 32 | * Java IO Streams 33 | * Spring Integration uses JMS adapters to send and receive JMS messages and JDBC adapters to convert messages to database queries and result sets back to messages. 34 | * Non software examples: power supply adapters, card readers and adapters, etc. 35 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/adapter/TextFormattable.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.adapter; 2 | 3 | /** 4 | * An example of the target interface that clients communicate with 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public interface TextFormattable { 10 | 11 | String formatText(String text, String separator); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/bridge/AppTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.bridge; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Client app for demo of bridge pattern 8 | * 9 | * @author tirthalp 10 | * 11 | */ 12 | public class AppTestDrive { 13 | 14 | public static void main(String[] args) { 15 | 16 | // --- Custom example of bridge between Vehicle abstractions and Workshop concrete implementations 17 | 18 | List workshops = new ArrayList<>(); 19 | workshops.add(new Produce()); 20 | workshops.add(new Assemble()); 21 | 22 | Vehicle vehicle1 = new Car(workshops); 23 | vehicle1.manufacture(); 24 | Vehicle vehicle2 = new Bike(workshops); 25 | vehicle2.manufacture(); 26 | 27 | // How abstractions and implementations can be independently extensible? 28 | // Try adding 'Truck extends Vehicle' or 'QualityAudit extends Workshop' independently. 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/bridge/Assemble.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.bridge; 2 | 3 | /** 4 | * an example Concrete implementation 2 for bridge pattern 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class Assemble implements Workshop { 10 | 11 | @Override 12 | public void work() { 13 | System.out.println("-> Assembled "); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/bridge/Bike.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.bridge; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * An example of Refined abstraction 2 in bridge pattern 7 | * 8 | * @author tirthalp 9 | * 10 | */ 11 | public class Bike extends Vehicle { 12 | 13 | public Bike(List workShops) { 14 | super(workShops); 15 | } 16 | 17 | @Override 18 | public String getVehicleType() { 19 | return "Bike "; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/bridge/Car.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.bridge; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * An example of Refined abstraction 1 in bridge pattern 7 | * 8 | * @author tirthalp 9 | * 10 | */ 11 | public class Car extends Vehicle { 12 | 13 | public Car(List workShops) { 14 | super(workShops); 15 | } 16 | 17 | @Override 18 | public String getVehicleType() { 19 | return "Car "; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/bridge/Produce.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.bridge; 2 | 3 | /** 4 | * An example Concrete implementation 1 for bridge pattern 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class Produce implements Workshop { 10 | 11 | @Override 12 | public void work() { 13 | System.out.print("-> Produced "); 14 | } 15 | } -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/bridge/README.md: -------------------------------------------------------------------------------- 1 | # Bridge Pattern 2 | 3 | To separate the abstract elements of a class from the implementation details, providing the means to replace the implementation details without modifying the abstraction. 4 | 5 | ## Usage / Concepts 6 | 7 | Decouples the functional abstraction from the implementation so that the two can vary independently. Use when, 8 | 9 | * Abstractions and implementations should not be bound at compile time. 10 | * Abstractions and implementations should be independently extensible. 11 | * Changes in the implementation of an abstraction should have no impact on clients. 12 | * Implementation details should be hidden from the client. 13 | 14 | ## See it in Action / Sample Code Snippet 15 | 16 | * Run [AppTestDrive.java](https://github.com/tirthalpatel/Learning-OOPD/blob/master/DesignPatterns/src/com/tirthal/learning/design/patterns/structural/bridge/AppTestDrive.java) client and refer the corresponding code flow. 17 | * Vehicle: Abstraction, which contains reference to the implementer. 18 | * Car, Bike: Refined Abstraction. 19 | * Workshop: Implementer. 20 | * Assemble, Produce: Concrete Implementation of the Implementer. 21 | * Abstractions and implementations can be independently extensible, i.e., add 'Truck extends Vehicle' or 'QualityAudit extends Workshop' independently. 22 | * see [Before Bridge Design Pattern vs. After Bridge Design Pattern](http://javapapers.com/design-patterns/bridge-design-pattern/) 23 | 24 | ## Key Design Considerations 25 | 26 | * Create two different hierarchies. One for abstraction and another for implementation. Create a bridge that coordinates between abstraction and implementation. 27 | * Avoid permanent binding by removing the dependency between abstraction and implementation. Decouple abstraction and implementation using Encapsulation, Composition and Inheritance techniques. 28 | * Abstraction and implementation can be extended separately. Should be used when we have need to switch implementation at runtime. 29 | * Client should not be impacted, if there is modification in implementation of abstraction. 30 | * The classes/objects participating in bridge pattern: 31 | * Abstraction: Core of the bridge design pattern and defines the crux. Contains a reference to the implementer. 32 | * Refined Abstraction: Extends the abstraction takes the finer detail one level below. Hides the finer elements from implementers. 33 | * Implementer: This interface is the higher level than abstraction. Just defines the basic operations. 34 | * Concrete Implementation: Implements the above implementer by providing concrete implementation. 35 | 36 | ## Real World Examples 37 | 38 | * JDBC Drivers -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/bridge/Vehicle.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.bridge; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * An example of abstraction in bridge pattern 7 | * 8 | * @author tirthalp 9 | * 10 | */ 11 | public abstract class Vehicle { 12 | protected List workshops; 13 | 14 | protected Vehicle(List workshops) { 15 | this.workshops = workshops; 16 | } 17 | 18 | public void manufacture() { 19 | System.out.print(getVehicleType()); 20 | 21 | for(Workshop workshop : workshops) { 22 | workshop.work(); 23 | } 24 | } 25 | 26 | abstract public String getVehicleType(); 27 | } 28 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/bridge/Workshop.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.bridge; 2 | 3 | /** 4 | * An example of Implementor for bridge pattern 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public interface Workshop { 10 | 11 | abstract public void work(); 12 | } 13 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/composite/AppTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.composite; 2 | 3 | /** 4 | * Client app for demo of composite pattern 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class AppTestDrive { 10 | 11 | public static void main(String[] args) { 12 | 13 | // --- Custom example hierarchical representations of Menu 14 | 15 | MenuComponent home = new Menu("Home", "/"); 16 | 17 | MenuComponent products = new Menu("Products", "/all-products"); 18 | products.add(new MenuItem("Product-1", "/p1")); 19 | products.add(new MenuItem("Product-1", "/p1")); 20 | home.add(products); 21 | 22 | MenuComponent contact = new MenuItem("Contact", "/contact"); 23 | home.add(contact); 24 | 25 | System.out.println(home.toString()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/composite/Menu.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.composite; 2 | 3 | import java.util.Iterator; 4 | 5 | /** 6 | * An example of Composite in composite pattern. 7 | * 8 | * @author tirthalp 9 | * 10 | */ 11 | public class Menu extends MenuComponent { 12 | 13 | public Menu(String name, String url) { 14 | this.name = name; 15 | this.url = url; 16 | } 17 | 18 | public MenuComponent add(MenuComponent menuComponent) { 19 | menuComponents.add(menuComponent); 20 | return menuComponent; 21 | } 22 | 23 | public MenuComponent remove(MenuComponent menuComponent) { 24 | menuComponents.remove(menuComponent); 25 | return menuComponent; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | 31 | StringBuilder sb = new StringBuilder(); 32 | sb.append(print(this)); 33 | 34 | Iterator itr = menuComponents.iterator(); 35 | while (itr.hasNext()) { 36 | MenuComponent mc = itr.next(); 37 | sb.append(mc.toString()); 38 | } 39 | 40 | return sb.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/composite/MenuComponent.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.composite; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * An example of Component in composite pattern. 8 | * 9 | * @author tirthalp 10 | * 11 | */ 12 | public abstract class MenuComponent { 13 | 14 | List menuComponents = new ArrayList(); 15 | String name; 16 | String url; 17 | 18 | public String getName() { 19 | return name; 20 | } 21 | 22 | public String getUrl() { 23 | return url; 24 | } 25 | 26 | public abstract String toString(); 27 | 28 | public MenuComponent add(MenuComponent menuComponent) { 29 | throw new UnsupportedOperationException("This feature is not implemented at this level."); 30 | } 31 | 32 | public MenuComponent remove(MenuComponent menuComponent) { 33 | throw new UnsupportedOperationException("This feature is not implemented at this level."); 34 | } 35 | 36 | public String print(MenuComponent menuComponent) { 37 | return new StringBuilder(name).append(" : ").append(url).append("\n").toString(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/composite/MenuItem.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.composite; 2 | 3 | /** 4 | * An example of Leaf in composite pattern. 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class MenuItem extends MenuComponent { 10 | 11 | public MenuItem(String name, String url) { 12 | this.name = name; 13 | this.url = url; 14 | } 15 | 16 | @Override 17 | public String toString() { 18 | return print(this); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/composite/README.md: -------------------------------------------------------------------------------- 1 | # Composite Pattern 2 | 3 | To create hierarchical, recursive tree structures of related objects where any element of the structure may be accessed and utilized in a standard manner. 4 | 5 | ## Usage / Concepts 6 | 7 | * Facilitates the creation of object hierarchies where each object can be treated independently or as a set of nested objects through the same interface. 8 | * Use when, 9 | - Hierarchical representations of objects are needed. 10 | - Objects and compositions of objects should be treated uniformly. 11 | 12 | ## See it in Action / Sample Code Snippet 13 | 14 | * Run [AppTestDrive.java](https://github.com/tirthalpatel/Learning-OOPD/blob/master/DesignPatterns/src/com/tirthal/learning/design/patterns/structural/composite/AppTestDrive.java) client and refer the corresponding code flow. 15 | * MenuComponent: Component. 16 | * MenuItem: Leaf. 17 | * Menu: Composite. 18 | 19 | ## Key Design Considerations 20 | 21 | * Tree structured - Component, Leaf, Composite, in which Leaf and Composite have the same interface 22 | * The classes/objects participating in composite pattern: 23 | * Component: Declares interface for objects in composition; Implements default behavior for the interface common to all classes as appropriate; Declares an interface for accessing and managing its child components. 24 | * Leaf: Represents leaf objects in composition; A leaf has no children; Defines behavior for primitive objects in the composition. 25 | * Composite: Defines behavior for components having children; Stores child component; Implements child related operations in the component interface. 26 | * Client: Manipulates objects in the composition through the component interface. 27 | 28 | ## Real World Examples 29 | 30 | * [java.awt.Component#add(Component)](https://docs.oracle.com/javase/7/docs/api/java/awt/Container.html#add(java.awt.Component)) 31 | * JSF Widgets -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/decorator/AppTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.decorator; 2 | 3 | import java.io.DataOutputStream; 4 | import java.io.File; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.io.OutputStream; 8 | 9 | /** 10 | * Client app for demo of decorator pattern to prepare beverage with choice of condiments 11 | * 12 | * @author tirthalp 13 | * 14 | */ 15 | public class AppTestDrive { 16 | 17 | public static void main(String args[]) throws IOException { 18 | 19 | // --- Real world example - OutputStream 20 | 21 | File f = new File("./target/temp.txt"); 22 | f.createNewFile(); 23 | 24 | OutputStream os = new FileOutputStream(f); 25 | DataOutputStream dos = new DataOutputStream(os); 26 | dos.writeChars("Hello World!"); 27 | dos.close(); 28 | 29 | // --- Custom decorator patter example 30 | 31 | // Select type of beverage 32 | Beverage beverage = new RedTea(); 33 | 34 | // Decorate with condiments like milk, sugar, tea masala... 35 | beverage = new Milk(beverage); 36 | beverage = new Sugar(beverage); 37 | beverage = new TeaMasala(beverage); 38 | 39 | // Print beverage and opted condiments description along with total price 40 | System.out.println("Total cost of '" + beverage.getDescription() + "' = Rs. " + beverage.cost()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/decorator/Beverage.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.decorator; 2 | 3 | /** 4 | * Beverage is supertype, which will offer each subclass concreate components to be used on its own, or wrapped by decorator component 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public abstract class Beverage { 10 | 11 | String description = "Unknown Beverage"; 12 | 13 | public String getDescription() { 14 | return description; 15 | } 16 | 17 | // enforce to implement cost method in the sub class 18 | public abstract double cost(); 19 | } 20 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/decorator/CondimentDecorator.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.decorator; 2 | 3 | /** 4 | * This is abstract class for decorators. It extends Beverage, because we need to be interchangeable with a Beverage. 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public abstract class CondimentDecorator extends Beverage { 10 | 11 | // enforce to implement getDescription method in the condiments sub classes 12 | public abstract String getDescription(); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/decorator/Milk.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.decorator; 2 | 3 | /** 4 | * Milk is-a type of condiment, which is example of the concrete decorator class. 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class Milk extends CondimentDecorator { 10 | 11 | // An instance variable to hold the beverage we are wrapping 12 | Beverage beverage; 13 | 14 | // A way to set this instance variable to the object we are wrapping 15 | public Milk(Beverage beverage) { 16 | this.beverage = beverage; 17 | } 18 | 19 | // First delegate to the object we are decorating get its description, and then append description for this condiment 20 | public String getDescription() { 21 | return beverage.getDescription() + ", Milk"; 22 | } 23 | 24 | // First we delegate the call to the object we're decorating, so that it can compute the cost, and then add the cost of this condiment to the result 25 | public double cost() { 26 | return beverage.cost() + 1.00; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/decorator/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPatterns/src/com/tirthal/learning/design/patterns/structural/decorator/README.md -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/decorator/RedTea.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.decorator; 2 | 3 | /** 4 | * Rea Tea is-a type of beverage. 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class RedTea extends Beverage { 10 | 11 | public RedTea() { 12 | description = "Red Tea"; 13 | } 14 | 15 | public double cost() { 16 | return 5.00; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/decorator/Sugar.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.decorator; 2 | 3 | /** 4 | * Sugar is-a type of condiment, which is example of the concrete decorator class. 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class Sugar extends CondimentDecorator { 10 | 11 | // An instance variable to hold the beverage we are wrapping 12 | Beverage beverage; 13 | 14 | // A way to set this instance variable to the object we are wrapping 15 | public Sugar(Beverage beverage) { 16 | this.beverage = beverage; 17 | } 18 | 19 | // First delegate to the object we are decorating get its description, and then append description for this condiment 20 | public String getDescription() { 21 | return beverage.getDescription() + ", Sugar"; 22 | } 23 | 24 | // First we delegate the call to the object we're decorating, so that it can compute the cost, and then add the cost of this condiment to the result 25 | public double cost() { 26 | return beverage.cost() + 1.00; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /DesignPatterns/src/com/tirthal/learning/design/patterns/structural/decorator/TeaMasala.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.design.patterns.structural.decorator; 2 | 3 | /** 4 | * Tea Masala is-a type of condiment, which is example of the concrete decorator class. 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class TeaMasala extends CondimentDecorator { 10 | 11 | // An instance variable to hold the beverage we are wrapping 12 | Beverage beverage; 13 | 14 | // A way to set this instance variable to the object we are wrapping 15 | public TeaMasala(Beverage beverage) { 16 | this.beverage = beverage; 17 | } 18 | 19 | // First delegate to the object we are decorating get its description, and then append description for this condiment 20 | public String getDescription() { 21 | return beverage.getDescription() + ", Tea Masala"; 22 | } 23 | 24 | // First we delegate the call to the object we're decorating, so that it can compute the cost, and then add the cost of this condiment to the result 25 | public double cost() { 26 | return beverage.cost() + 1.00; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /DesignPrinciples/.gitignore: -------------------------------------------------------------------------------- 1 | /.settings/ 2 | /target/ 3 | /.classpath 4 | /.project 5 | -------------------------------------------------------------------------------- /DesignPrinciples/README.md: -------------------------------------------------------------------------------- 1 | Learn OOP Design Principles 2 | =========================== 3 | 4 | This project is created for sharing sample java code (by practical examples along with easy to understand comments) to learn object oriented programming concepts and design principles. 5 | 6 | How to use? - Just import this project in Eclipse an "Existing Maven Project". If require, do necessary configuration to fix build path errors (e.g. setup JRE 1.8). 7 | 8 | For more detail, please read [here](http://tirthalpatel.blogspot.in/2014/01/oop-design-fundamentals-and-principles.html) 9 | 10 | 11 | Object oriented programming concepts 12 | ------------------------------------ 13 | 14 | Refer package - [com.tirthal.learning.oop.concepts](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPrinciples/src/com/tirthal/learning/oop/concepts) 15 | 16 | For more detail, please read [here](http://tirthalpatel.blogspot.in/2014/01/oop-design-part-1-fundamentals.html) 17 | 18 | 19 | Class design principles - SOLID 20 | -------------------------------- 21 | 22 | Refer package - [com.tirthal.learning.oop.design.principles.clazz.solid](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid) 23 | 24 | For more detail, please read [here](http://tirthalpatel.blogspot.in/2014/04/oop-design-part-2-class-principles-solid.html) 25 | 26 | 27 | Class design principles - GRASP 28 | ------------------------------- 29 | 30 | Refer package - com.tirthal.learning.oop.design.principles.clazz.grasp 31 | 32 | TODO - To be added... 33 | 34 | 35 | Package design principles 36 | ------------------------- 37 | 38 | Refer package - com.tirthal.learning.oop.design.principles.package 39 | 40 | TODO - To be added... -------------------------------------------------------------------------------- /DesignPrinciples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | DesignPrinciples 6 | DesignPrinciples 7 | jar 8 | 0.0.1-SNAPSHOT 9 | Sample code snippet to learn object oriented programming concepts and design principles 10 | 11 | 12 | src 13 | 14 | 15 | org.apache.maven.plugins 16 | maven-compiler-plugin 17 | 2.3.2 18 | 19 | 1.8 20 | 1.8 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/README.md: -------------------------------------------------------------------------------- 1 | For more detail, please read [here](http://tirthalpatel.blogspot.in/2014/01/oop-design-fundamentals-and-principles.html) -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/concepts/AggregationComposition_TestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.concepts; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | //--------------------------------------- 7 | //--- STEP 00 - WHAT IS AGGREGATION & COMPOSITION? 8 | //--------------------------------------- 9 | 10 | ///** 11 | // * Aggregation = HAS-A Relationship. 12 | // * 13 | // * Aggregation is an association represents a part of a whole relationship where a part can exist without a whole. 14 | // * It has a weaker relationship. For example, If line-item HAS-A product, then a line item is a whole and product is a part. 15 | // * If a line item is deleted, then corresponding product needs not to be deleted. 16 | // */ 17 | 18 | ///** 19 | // * Composition = HAS-A relationship, but restricted form of Aggregation 20 | // * 21 | // * Composition is an association represents a part of a whole relationship where a part cannot exist without a whole. If a whole is deleted then 22 | // * all parts are deleted. It has a stronger relationship. For example, if order HAS-A line-items, then an order is a whole and line items are parts. 23 | // * If an order is deleted then all corresponding line items for that order should be deleted. 24 | // */ 25 | 26 | // --------------------------------------- 27 | // --- STEP 01 - UNDERSTAND AGGREGATION & COMPOSITION BY EXAMPLE 28 | // --------------------------------------- 29 | 30 | /** 31 | * This is test class for aggregation and composition example 32 | * 33 | * @author tirthalp 34 | * 35 | */ 36 | public class AggregationComposition_TestDrive { 37 | public static void main(String[] args) { 38 | // Create Products 39 | Product p1 = new Product(1, "Pen", "This is red pen"); 40 | Product p2 = new Product(2, "Pencil", "This is pencil"); 41 | Product p3 = new Product(3, "ColorBox", "This is color box"); 42 | 43 | // Create Order and Add Line Items 44 | Order o = new Order(1, "ORD#1"); 45 | o.addItem(1, 2, p1); // Ordered of 2 quantity for p1 product 46 | o.addItem(2, 1, p2); // Ordered of 1 quantity for p2 product 47 | o.addItem(3, 5, p3); // Ordered of 5 quantity for p3 product 48 | // Print Order detail before deleting 49 | System.out.println("Order ---"); 50 | System.out.println(o); 51 | // Deleting order would also delete associated LineItems ------- Represents Composition relationship between Order and LineItem 52 | o = null; 53 | // Line items are deleted, but associated products can still exist -------- Represents Aggregation relationship between LineItem and Product 54 | System.out.println("Products ---"); 55 | System.out.println(p1); 56 | System.out.println(p2); 57 | System.out.println(p3); 58 | } 59 | } 60 | 61 | /** 62 | * This is Product class 63 | * 64 | * @author tirthalp 65 | * 66 | */ 67 | class Product { 68 | private int id; 69 | private String name; 70 | private String description; 71 | 72 | public Product(int id, String name, String description) { 73 | super(); 74 | this.id = id; 75 | this.name = name; 76 | this.description = description; 77 | } 78 | public int getId() { 79 | return id; 80 | } 81 | public void setId(int id) { 82 | this.id = id; 83 | } 84 | public String getName() { 85 | return name; 86 | } 87 | public void setName(String name) { 88 | this.name = name; 89 | } 90 | public String getDescription() { 91 | return description; 92 | } 93 | public void setDescription(String description) { 94 | this.description = description; 95 | } 96 | @Override 97 | public String toString() { 98 | return "Product [id=" + id + ", name=" + name + ", description=" + description + "]"; 99 | } 100 | } 101 | 102 | /** 103 | * This is LineItem class, which HAS-A aggregation association with Product class. That means, if you delete LineItem, then associated Product can 104 | * exist. 105 | * 106 | * @author tirthalp 107 | * 108 | */ 109 | class LineItem { 110 | private int id; 111 | private int quantity; 112 | private Product p; 113 | 114 | public LineItem(int id, int quantity, Product p) { 115 | super(); 116 | this.id = id; 117 | this.quantity = quantity; 118 | this.p = p; 119 | } 120 | public int getId() { 121 | return id; 122 | } 123 | public void setId(int id) { 124 | this.id = id; 125 | } 126 | public int getQuantity() { 127 | return quantity; 128 | } 129 | public void setQuantity(int quantity) { 130 | this.quantity = quantity; 131 | } 132 | public Product getP() { 133 | return p; 134 | } 135 | public void setP(Product p) { 136 | this.p = p; 137 | } 138 | @Override 139 | public String toString() { 140 | return "LineItem [id=" + id + ", quantity=" + quantity + ", p=" + p + "]"; 141 | } 142 | } 143 | 144 | /** 145 | * This is Order class, which HAS-A composition association with LineItem class. That means if you delete Order, then associated all LineItem must be 146 | * deleted. 147 | * 148 | * @author tirthalp 149 | * 150 | */ 151 | class Order { 152 | private int id; 153 | private String name; 154 | private List lineItems; 155 | 156 | public Order(int id, String name) { 157 | super(); 158 | this.id = id; 159 | this.name = name; 160 | this.lineItems = new ArrayList(); 161 | } 162 | public int getId() { 163 | return id; 164 | } 165 | public void setId(int id) { 166 | this.id = id; 167 | } 168 | public String getName() { 169 | return name; 170 | } 171 | public void setName(String name) { 172 | this.name = name; 173 | } 174 | 175 | @Override 176 | public String toString() { 177 | return "Order [id=" + id + ", name=" + name + ", lineItems=" + lineItems + "]"; 178 | } 179 | 180 | // Add line item to order 181 | public void addItem(int id, int quantity, Product p) { 182 | this.lineItems.add(new LineItem(id, quantity, p)); 183 | } 184 | 185 | // Remove line item from order for given item id 186 | public void removeItemById(int itemId) { 187 | // TODO - Not implemented yet 188 | } 189 | } -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/concepts/Cohesion_TestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.concepts; 2 | 3 | //--------------------------------------- 4 | //--- STEP 00 - WHAT IS HIGH COHESION? 5 | //--------------------------------------- 6 | 7 | ///** 8 | // * High Cohesion = The responsibilities/methods are highly related to class/module. 9 | // * 10 | // * The term cohesion is used to indicate the degree to which a class has a single, well-focused. Cohesion is a measure of how the methods of a class 11 | // * or a module are meaningfully and strongly related and how focused they are in providing a well-defined purpose to the system. The more focused a 12 | // * class is, the higher its cohesiveness - a good thing. 13 | // * 14 | // * A class is identified as a low cohesive class, when it contains many unrelated functions within it. And that what we need to avoid, because big 15 | // * classes with unrelated functions hamper their maintaining. Always make your class small and with precise purpose and highly related functions. 16 | // */ 17 | 18 | //--------------------------------------- 19 | //--- STEP 01 - EXAMPLE OF LOW COHESIVE CLASS 20 | //--------------------------------------- 21 | 22 | /** 23 | * The purpose of "MyReader" is to read the resource. But it contains some unrelated functions such as validateLocation(), checkFTP(), ping(). Hence 24 | * it is low cohesive. 25 | * 26 | * @author tirthalp 27 | * 28 | */ 29 | class MyReader_LowCohesive { 30 | 31 | // -------------- unrelated functions 32 | 33 | public boolean validateLocation(String pathIP) { 34 | return ping(pathIP) && checkFTP(pathIP); 35 | } 36 | 37 | private boolean checkFTP(String pathIP) { 38 | // TODO Add logic 39 | return true; 40 | } 41 | 42 | private boolean ping(String pathIP) { 43 | // TODO Add logic 44 | return true; 45 | } 46 | 47 | // -------------- functions related to read resource 48 | 49 | // read the resource from disk 50 | public String readFromDisk(String fileName) { 51 | return "data of " + fileName; 52 | } 53 | 54 | // read the resource from web 55 | public String readFromWeb(String url) { 56 | return "data of " + url; 57 | } 58 | 59 | // read the resource from network 60 | public String readFromNetwork(String networkAddress) { 61 | return "data of " + networkAddress; 62 | } 63 | 64 | } 65 | 66 | // --------------------------------------- 67 | // --- STEP 02 - EXAMPLE OF HIGH COHESIVE CLASS 68 | // --------------------------------------- 69 | 70 | /** 71 | * The purpose of "MyReader" is to read the resource and it does that only. It does not implement other unrelated things. Hence it is highly cohesive. 72 | * 73 | * @author tirthalp 74 | * 75 | */ 76 | class MyReader_HighCohesive { 77 | // -------------- functions related to read resource 78 | 79 | // read the resource from disk 80 | public String readFromDisk(String fileName) { 81 | return "reading data of " + fileName; 82 | } 83 | 84 | // read the resource from web 85 | public String readFromWeb(String url) { 86 | return "reading data of " + url; 87 | } 88 | 89 | // read the resource from network 90 | public String readFromNetwork(String networkAddress) { 91 | return "reading data of " + networkAddress; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/concepts/Delegation_InsteadOfGetterSetter_TestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.concepts; 2 | 3 | //--------------------------------------- 4 | //--- STEP 00 - LEARN DESIGN PRINCIPLE TO DEFINE BEHAVIOR 5 | //--------------------------------------- 6 | 7 | // To define behavior, always consider to use "delegation" over offer data access via getter/setter methods 8 | 9 | //--------------------------------------- 10 | //--- STEP 01 - UNDERSTAND DELEGATION OVER GETTER/SETTER APPROACH BY EXAMPLE 11 | //--------------------------------------- 12 | 13 | /** 14 | * 15 | * 16 | * @author tirthalp 17 | * @see Delegation_TestDrive 18 | */ 19 | public class Delegation_InsteadOfGetterSetter_TestDrive { 20 | 21 | public static void main(String[] args) { 22 | // ----------------------- 23 | // --- STEP 03 - See why getter/setter are evil? 24 | // ----------------------- 25 | Temperature1 temp1 = new Temperature1(100.0, TemperatureUnit.FAHRENHEIT); 26 | Temperature1 temp2 = new Temperature1(36.888, TemperatureUnit.CELSIUS); 27 | 28 | // Let's do something, if temp1 is higher than temp2 29 | double temp1InCelsius = ((temp1.getValue() - 32) * 5) / 9; // normalize to celsius 30 | double temp2InCelsius = temp2.getValue(); 31 | 32 | if (temp1InCelsius > temp2InCelsius) 33 | System.out.println("Do some client specific operation..."); 34 | 35 | /* 36 | * What's problem? 37 | * 38 | * Well, client code will become big and complex as need to add more functionality like adding Kelvin in 39 | * TemperatureUnit. 40 | * 41 | * Ideally, the Temperature1 class has the information, so it should be doing the comparison as per Delegation 42 | * principle. So getting the temperature value and doing comparison outside of the Temperature1 class is not at 43 | * all an acceptable solution. 44 | */ 45 | 46 | // ----------------------- 47 | // --- STEP 04 - See how delegation helps to solve above problem and simply client code? 48 | // ----------------------- 49 | Temperature2 temp3 = new Temperature2(100.0, TemperatureUnit.FAHRENHEIT); 50 | Temperature2 temp4 = new Temperature2(36.888, TemperatureUnit.CELSIUS); 51 | 52 | if (temp3.isGreaterThan(temp4)) 53 | System.out.println("Do some client specific operation..."); 54 | 55 | /* 56 | * Awesome, this is greatly simplified client code. 57 | * 58 | * Learning = Temperature2 class has data, client code should delegate temperature normalization and comparison 59 | * responsibility to the Temperature2 class. Adding Kelvin support in TemperatureUnit would not impact client 60 | * code anymore. 61 | */ 62 | } 63 | } 64 | 65 | // An enum of temperature units 66 | enum TemperatureUnit { 67 | CELSIUS, FAHRENHEIT; 68 | } 69 | 70 | // A class with getter/setter 71 | class Temperature1 { 72 | private double value; 73 | private TemperatureUnit unit; 74 | 75 | public Temperature1(double value, TemperatureUnit unit) { 76 | this.value = value; 77 | this.unit = unit; 78 | } 79 | 80 | public double getValue() { 81 | return value; 82 | } 83 | 84 | public void setValue(double value) { 85 | this.value = value; 86 | } 87 | 88 | public TemperatureUnit getUnit() { 89 | return unit; 90 | } 91 | 92 | public void setUnit(TemperatureUnit unit) { 93 | this.unit = unit; 94 | } 95 | } 96 | 97 | // A class having temperature comparison behavior, as it has data to do this job 98 | class Temperature2 { 99 | private double value; 100 | private TemperatureUnit unit; 101 | 102 | public Temperature2(double value, TemperatureUnit unit) { 103 | this.value = value; 104 | this.unit = unit; 105 | } 106 | 107 | public boolean isGreaterThan(Temperature2 temp4) { 108 | return this.normalizedToCelsius() > temp4.normalizedToCelsius(); 109 | } 110 | 111 | private double normalizedToCelsius() { 112 | return this.unit == TemperatureUnit.CELSIUS ? this.value : ((this.value - 32) * 5) / 9; 113 | } 114 | } -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/concepts/Delegation_TestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.concepts; 2 | 3 | //--------------------------------------- 4 | //--- STEP 00 - WHAT IS DELEGATION? 5 | //--------------------------------------- 6 | 7 | ///** 8 | // * Delegation = hand over the responsibility for a particular task to another class or method. 9 | // * 10 | // * Ask for help, not for information. Don't get() the data. Ask the object that has the data to do the work for you. The object that has the information does the work. 11 | // * 12 | // * If you need to use functionality in another class but you do not want to change that functionality then use delegation instead of inheritance. 13 | // */ 14 | 15 | //--------------------------------------- 16 | //--- STEP 01 - UNDERSTAND DELEGATION (ALONG WITH POLYMORPHISM) BY EXAMPLE 17 | //--------------------------------------- 18 | 19 | /** 20 | * This is test class for the delegation and polymorphism example 21 | * 22 | * @author tirthalp 23 | * @see Delegation_InsteadOfGetterSetter_TestDrive 24 | */ 25 | public class Delegation_TestDrive { 26 | 27 | public static void main(String[] args) { 28 | // Here TicketBookingByAgent class is internally delegating train ticket booking responsibility to other class 29 | TicketBookingByAgent agent = new TicketBookingByAgent(new TrainBooking()); 30 | agent.bookTicket(); 31 | 32 | // Here TicketBookingByAgent class is internally delegating airline ticket booking responsibility to other class 33 | agent = new TicketBookingByAgent(new AirBooking()); 34 | agent.bookTicket(); 35 | } 36 | } 37 | 38 | /** 39 | * TicketBokkingByAgent provides implementation of TravelBooking. But it delegates actual ticket booking to other class at runtime using Polymorphism. 40 | * 41 | * @author tirthalp 42 | * 43 | */ 44 | class TicketBookingByAgent implements TravelBooking { 45 | 46 | TravelBooking t; 47 | 48 | public TicketBookingByAgent(TravelBooking t) { 49 | this.t = t; 50 | } 51 | 52 | // Delegation --- Here ticket booking responsibility is delegated to other class using polymorphism 53 | @Override 54 | public void bookTicket() { 55 | t.bookTicket(); 56 | } 57 | } 58 | 59 | /** 60 | * This represents TravelBooking interface 61 | * 62 | * @author tirthalp 63 | * 64 | */ 65 | interface TravelBooking { 66 | public void bookTicket(); 67 | } 68 | 69 | /** 70 | * TrainBooking IS-A TravelBooking type 71 | * 72 | * @author tirthalp 73 | * 74 | */ 75 | class TrainBooking implements TravelBooking { 76 | @Override 77 | public void bookTicket() { 78 | System.out.println("Train ticket booked"); 79 | } 80 | } 81 | 82 | /** 83 | * AirBooking IS-A TravelBooking type 84 | * 85 | * @author tirthalp 86 | * 87 | */ 88 | class AirBooking implements TravelBooking { 89 | @Override 90 | public void bookTicket() { 91 | System.out.println("Flight ticket booked"); 92 | } 93 | } -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/concepts/Encapsulation_TestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.concepts; 2 | 3 | //--------------------------------------- 4 | //--- STEP 00 - WHAT IS ABSTRACTION & ENCAPSULATION? 5 | //--------------------------------------- 6 | 7 | ///** 8 | // * Abstraction = Looking only at the information that is relevant at the time. 9 | // * 10 | // * Abstraction is the process or result of generalization by reducing the information content of a concept or an observable phenomenon, 11 | // * typically in order to retain only information which is relevant for a particular purpose. It is starting point of design. 12 | // * Functional abstraction - means that a function can be used without taking into account how the function is implemented. 13 | // * Data Abstraction - means that data can be used without taking into account how the data are stored. 14 | // */ 15 | 16 | ///** 17 | // * Encapsulation = Data hiding mechanism. 18 | // * 19 | // * The process of binding or wrapping the data and the codes that operates on the data into a single entity. This keeps the data safe from 20 | // * outside interface and misuse. One way to think about encapsulation is as a protective wrapper that prevents code and data from being arbitrarily 21 | // * accessed by other code defined outside the wrapper. 22 | // * For example - if a field is declared private, it cannot be accessed by anyone outside the class, thereby hiding the fields within the class. 23 | // */ 24 | 25 | //--------------------------------------- 26 | //--- STEP 01 - UNDERSTAND ENCAPSULATION BY EXAMPLE 27 | //--------------------------------------- 28 | 29 | /** 30 | * 31 | * Encapsulation goals of Person class 32 | * 33 | * (1) The id and name parameters should not be accessible directly outside Person class - achieved by private declaration 34 | * 35 | * (2) The id value can be assigned in Person class only and other class should not be able to change - not included setId() method 36 | * 37 | * @author tirthalp 38 | * 39 | */ 40 | class Person { 41 | 42 | private double id; 43 | private String name; 44 | 45 | public Person() { 46 | // Only Person class can access and assign 47 | id = Math.random(); 48 | sayHello(); 49 | } 50 | 51 | // This method is protected for giving access within Person class only 52 | private void sayHello() { 53 | System.out.println("Hello - " + getId()); 54 | } 55 | 56 | public double getId() { 57 | return id; 58 | } 59 | 60 | public String getName() { 61 | return name; 62 | } 63 | public void setName(String name) { 64 | this.name = name; 65 | } 66 | } 67 | 68 | /** 69 | * Test class for Person 70 | * 71 | * @author tirthalp 72 | * 73 | */ 74 | public class Encapsulation_TestDrive { 75 | 76 | public static void main(String[] args) { 77 | 78 | Person p1 = new Person(); 79 | p1.setName("Tirthal"); 80 | /* 81 | * Note: As id and name are encapsulated in Person class, those cannot be accessed directly here. Also there is no way to assign id in this 82 | * class. Try to uncomment below code and you would find compile time error. 83 | */ 84 | // p1.id = "123"; 85 | // p1.name = "this will give compile time error"; 86 | // p1.sayHello(); // You can't access this method, as it is private to Person 87 | 88 | System.out.println("Person 1 - " + p1.getId() + " : " + p1.getName()); 89 | } 90 | } -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/concepts/Inheritance_TestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.concepts; 2 | 3 | //--------------------------------------- 4 | //--- STEP 00 - WHAT IS INHERITANCE? 5 | //--------------------------------------- 6 | 7 | ///** 8 | // * Inheritance = is-a relationship between a superclass and its subclasses. 9 | // * 10 | // * For example, Dog (subclass) is-a of type Animal (superclass). So Dog can inherit (reuse) members of Animal class; 11 | // * plus it can have its own new behavior and properties. 12 | // */ 13 | 14 | //--------------------------------------- 15 | //--- STEP 01 - UNDERSTAND INHERITANCE BY EXAMPLE 16 | //--------------------------------------- 17 | 18 | /** 19 | * Test class for inheritance behavior - Dog class is inheriting behavior and properties of Animal class and can have its own too. 20 | * 21 | * @author tirthalp 22 | * 23 | */ 24 | public class Inheritance_TestDrive { 25 | 26 | public static void main(String[] args) { 27 | Dog dog = new Dog(); 28 | dog.setId(123); // inherited from super class 29 | dog.sound(); // overrided behavior of sub class 30 | } 31 | } 32 | 33 | /** 34 | * This is parent (also called as super or base) class Animal 35 | * 36 | * @author tirthalp 37 | * 38 | */ 39 | class Animal { 40 | int id; 41 | 42 | public int getId() { 43 | return id; 44 | } 45 | 46 | public void setId(int id) { 47 | this.id = id; 48 | } 49 | 50 | public void sound() { 51 | System.out.println("By default it is mute"); 52 | } 53 | } 54 | 55 | /** 56 | * This is subclass (also called as derived or child or extended) Dog which is extending Animal 57 | * 58 | * @author tirthalp 59 | * 60 | */ 61 | class Dog extends Animal { 62 | 63 | // Own behavior 64 | private void bark() { 65 | System.out.println("Dog '" + getId() + "' is barking"); 66 | } 67 | 68 | // Overriding super class behavior 69 | @Override 70 | public void sound() { 71 | bark(); 72 | } 73 | } -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/concepts/LooseCoupling_TestDrive.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPrinciples/src/com/tirthal/learning/oop/concepts/LooseCoupling_TestDrive.java -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/concepts/Polymorphism_TestDrive.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPrinciples/src/com/tirthal/learning/oop/concepts/Polymorphism_TestDrive.java -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/concepts/README.md: -------------------------------------------------------------------------------- 1 | For more detail, please read [here](http://tirthalpatel.blogspot.in/2014/01/oop-design-part-1-fundamentals.html) -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/README.md: -------------------------------------------------------------------------------- 1 | S --- SRP = Single Responsibility Principle 2 | 3 | O --- OCP = Open Closed Principle 4 | 5 | L --- LSP = Liskov's Substitution Principle 6 | 7 | I --- ISP = Interface segregation principle 8 | 9 | D --- DIP = Dependency Inversion Principle 10 | 11 | 12 | For more detail, please read [here](http://tirthalpatel.blogspot.in/2014/04/oop-design-part-2-class-principles-solid.html) -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/dip/README.md: -------------------------------------------------------------------------------- 1 | *** DIP = Dependency Inversion Principle 2 | ----------------------------------------------- 3 | 4 | *** Description = 5 | 6 | - The Dependency Inversion Principle (DIP) states that high-level modules should not depend upon low-level modules; they should depend on abstractions. 7 | 8 | - Secondly, abstractions should not depend upon details; details should depend upon abstractions. The idea is that we isolate our class behind a boundary 9 | formed by the abstractions it depends on. If all the details behind those abstractions change, then our class is still safe. This helps keep coupling 10 | low and makes our design easier to change. DIP also allows us to test things in isolation, details like database are plugins to our system. 11 | 12 | ----------------------------------------------- 13 | 14 | *** Examples = 15 | 16 | (1) Authenticate (package = com.tirthal.learning.oop.design.principles.clazz.solid.dip.authentication) 17 | 18 | Requirement - Provide login by authenticating using Simple DB logic. In future, there may require adding more options such as LDAP based authentication. 19 | 20 | ------ First let's see "bad" design and implementation (package = com.tirthal.learning.oop.design.principles.clazz.solid.dip.authentication.bad) 21 | 22 | - Refer LoginManager.java and SimpleAuthenticator.java 23 | 24 | ------ How to do code-refactoring to make "good" design using DIP? (package = com.tirthal.learning.oop.design.principles.clazz.solid.dip.authentication.good) 25 | 26 | - Refer LoginManager.java 27 | - Refer SimpleAuthenticator.java and LDAPAuthenticator.java, which implements Authenticator.java interface 28 | 29 | ----------------------------------------------- 30 | 31 | Feel free to contribute code for more examples in similar fashion... :-) -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/dip/authentication/bad/LoginManager.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.dip.authentication.bad; 2 | 3 | /** 4 | * High level class for login. Why DIP is violated? 5 | * 6 | * In this example, the LoginManager class is directly dependent on SimpleAuthenticator, which has no abstractions and is the implementing 7 | * class. In case of new authentication mechanism in future, LoginManager would be changed and the unit testing should be redone. 8 | * 9 | * @author tirthalp 10 | * 11 | */ 12 | public class LoginManager { 13 | 14 | SimpleAuthenticator simpleAuthenticator = new SimpleAuthenticator(); 15 | 16 | public void login(User user) { 17 | simpleAuthenticator.authenticate(user); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/dip/authentication/bad/SimpleAuthenticator.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.dip.authentication.bad; 2 | 3 | /** 4 | * 5 | * Low level class of authentication 6 | * 7 | * @author tirthalp 8 | * 9 | */ 10 | public class SimpleAuthenticator { 11 | 12 | public boolean authenticate(User user) { 13 | 14 | // logic - database 15 | 16 | return true; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/dip/authentication/bad/User.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.dip.authentication.bad; 2 | 3 | public class User { 4 | 5 | private int id; 6 | 7 | public int getId() { 8 | return id; 9 | } 10 | 11 | public void setId(int id) { 12 | this.id = id; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/dip/authentication/good/Authenticator.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.dip.authentication.good; 2 | 3 | /** 4 | * The example low level interface to provide abstraction 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public interface Authenticator { 10 | 11 | boolean authenticate(User user); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/dip/authentication/good/LDAPAuthenticator.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.dip.authentication.good; 2 | 3 | /** 4 | * The example low level class, which would provide implementation of authentication by LDAP 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class LDAPAuthenticator implements Authenticator { 10 | 11 | @Override 12 | public boolean authenticate(User user) { 13 | // logic - LDAP 14 | return true; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/dip/authentication/good/LoginManager.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.dip.authentication.good; 2 | 3 | /** 4 | * High level class for login, which follows DIP. 5 | * 6 | * In this example, the LoginManager class is not directly dependent on SimpleAuthenticator or LDAPAuthenticator implementation class. Rather it depends 7 | * on Authenticator interface which provides abstractions. 8 | * 9 | * In case of adding new authentication mechanism in future, LoginManager and its unit test would not be changed. 10 | * 11 | * @author tirthalp 12 | * 13 | */ 14 | public class LoginManager { 15 | 16 | Authenticator authenticator; 17 | 18 | public void setAuthenticator(Authenticator authenticator) { 19 | this.authenticator = authenticator; 20 | } 21 | 22 | public void login(User user) { 23 | authenticator.authenticate(user); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/dip/authentication/good/SimpleAuthenticator.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.dip.authentication.good; 2 | 3 | /** 4 | * The example low level class, which would provide implementation of authentication by database 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class SimpleAuthenticator implements Authenticator { 10 | 11 | @Override 12 | public boolean authenticate(User user) { 13 | // logic - database 14 | return true; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/dip/authentication/good/User.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.dip.authentication.good; 2 | 3 | public class User { 4 | 5 | private int id; 6 | 7 | public int getId() { 8 | return id; 9 | } 10 | 11 | public void setId(int id) { 12 | this.id = id; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/isp/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/isp/README.md -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/isp/order/bad/Order.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.isp.order.bad; 2 | 3 | /** 4 | * The sample order POJO / Entity 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class Order { 10 | 11 | private int id; 12 | 13 | public int getId() { 14 | return id; 15 | } 16 | 17 | public void setId(int id) { 18 | this.id = id; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/isp/order/bad/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.isp.order.bad; 2 | 3 | /** 4 | * Why ISP is violated here in the order service design? Because, 5 | * 6 | * User client - Forced to depend on process order unnecessarily. 7 | * 8 | * Backend job client - only need process order, but still forced to depend on other services too. 9 | * 10 | * Note - To keep example in simplest form, I didn't consider exact low-level API design of the mentioned methods. 11 | * 12 | * @author tirthalp 13 | */ 14 | public interface OrderService { 15 | 16 | // ------------ Order services consumed by the user client 17 | 18 | /** 19 | * Create order 20 | * 21 | * @return new created order instance having unique id 22 | */ 23 | public Order createOrder(); 24 | 25 | /** 26 | * Change order 27 | * 28 | * @return updated order instance 29 | */ 30 | public Order amendOrder(); 31 | 32 | /** 33 | * Cancel order 34 | * 35 | * @param orderId 36 | * 37 | * @return status of order cancellation operation 38 | */ 39 | public boolean cancelOrder(int orderId); 40 | 41 | /** 42 | * Submit order 43 | * 44 | * @param orderId 45 | * @return submitted order instance 46 | */ 47 | public Order submitOrder(int orderId); 48 | 49 | /** 50 | * Get order detail by order id 51 | * 52 | * @param orderId 53 | * @return order instance for given orderId 54 | */ 55 | public Order getOrder(int orderId); 56 | 57 | // ------------ Order services consumed by the backend/integration job client 58 | 59 | /** 60 | * This is responsible for processing the order for delivery 61 | * 62 | * @return status of the order processed by job 63 | */ 64 | public boolean processOrder(int orderId); 65 | } 66 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/isp/order/good/Order.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.isp.order.good; 2 | 3 | /** 4 | * The sample order POJO / Entity 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class Order { 10 | 11 | private int id; 12 | 13 | public int getId() { 14 | return id; 15 | } 16 | 17 | public void setId(int id) { 18 | this.id = id; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/isp/order/good/OrderProcessingService.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.isp.order.good; 2 | 3 | /** 4 | * After refactoring, all services apart from processOrder() are kept in another interface. So now backend job client is not forced to depend on 5 | * those unnecessary OrderService(s). 6 | * 7 | * Note - To keep example in simplest form, I didn't consider exact low-level API design of the mentioned methods. 8 | * 9 | * @author tirthalp 10 | */ 11 | public interface OrderProcessingService { 12 | 13 | // ------------ Order services consumed by the backend/integration job client 14 | 15 | /** 16 | * This is responsible for processing the order for delivery 17 | * 18 | * @return status of the order processed by job 19 | */ 20 | public boolean processOrder(int orderId); 21 | } 22 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/isp/order/good/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.isp.order.good; 2 | 3 | /** 4 | * After refactoring, processOrder() is moved in another interface. So now user client is not forced to depend on it unnecessarily. 5 | * Also vice-versa is true, as backend job client is not forced to depend on OrderService. 6 | * 7 | * Note - To keep example in simplest form, I didn't consider exact low-level API design of the mentioned methods. 8 | * 9 | * @author tirthalp 10 | */ 11 | public interface OrderService { 12 | 13 | // ------------ Order services consumed by the user client 14 | 15 | /** 16 | * Create order 17 | * 18 | * @return new created order instance having unique id 19 | */ 20 | public Order createOrder(); 21 | 22 | /** 23 | * Change order 24 | * 25 | * @return updated order instance 26 | */ 27 | public Order amendOrder(); 28 | 29 | /** 30 | * Cancel order 31 | * 32 | * @param orderId 33 | * 34 | * @return status of order cancellation operation 35 | */ 36 | public boolean cancelOrder(int orderId); 37 | 38 | /** 39 | * Submit order 40 | * 41 | * @param orderId 42 | * @return submitted order instance 43 | */ 44 | public Order submitOrder(int orderId); 45 | 46 | /** 47 | * Get order detail by order id 48 | * 49 | * @param orderId 50 | * @return order instance for given orderId 51 | */ 52 | public Order getOrder(int orderId); 53 | } 54 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tirthalpatel/Learning-OOPD/4a591474a87912f1c8395083cec3dff02a0da6c5/DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/README.md -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/bad/ClientTestProgram.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.bad; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * This is sample client program which refers MediaPlayer 8 | * 9 | * @author tirthalp 10 | */ 11 | public class ClientTestProgram { 12 | 13 | public static void main(String[] args) { 14 | 15 | // Created list of players 16 | List allPlayers = new ArrayList(); 17 | allPlayers.add(new VlcMediaPlayer()); 18 | allPlayers.add(new DivMediaPlayer()); 19 | 20 | // Play video in all players 21 | playVideoInAllMediaPlayers(allPlayers); 22 | 23 | // Well - all works as of now...... :-) 24 | System.out.println("---------------------------"); 25 | 26 | // Now adding new Winamp player 27 | allPlayers.add(new WinampMediaPlayer()); 28 | 29 | // Again play video in all players & Oops it broke the program... :-( 30 | // Why we got unexpected behavior in client? --- Because LSP is violated in WinampMediaPlayer.java, as it changed the original behavior of super class MediaPlayer.java 31 | playVideoInAllMediaPlayers(allPlayers); 32 | } 33 | 34 | /** 35 | * This method is playing video in all players 36 | * 37 | * @param allPlayers 38 | */ 39 | public static void playVideoInAllMediaPlayers(List allPlayers) { 40 | 41 | for(MediaPlayer player : allPlayers) { 42 | player.playVideo(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/bad/DivMediaPlayer.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.bad; 2 | 3 | /** 4 | * Div Media player extending behavior of super class Media player. Perfect, LSP is not violated here. 5 | * 6 | * @author tirthalp 7 | */ 8 | public class DivMediaPlayer extends MediaPlayer { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/bad/MediaPlayer.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.bad; 2 | 3 | /** 4 | * Example media player super class which has ability to play video and audio 5 | * 6 | * @author tirthalp 7 | */ 8 | public class MediaPlayer { 9 | 10 | // Play audio implementation 11 | public void playAudio() { 12 | System.out.println("Playing audio..."); 13 | } 14 | 15 | // Play video implementation 16 | public void playVideo() { 17 | System.out.println("Playing video..."); 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/bad/VideoUnsupportedException.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.bad; 2 | 3 | public class VideoUnsupportedException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/bad/VlcMediaPlayer.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.bad; 2 | 3 | /** 4 | * VLC Media player extending behavior of super class Media player. Perfect, LSP is not violated here. 5 | * 6 | * @author tirthalp 7 | */ 8 | public class VlcMediaPlayer extends MediaPlayer { 9 | 10 | } -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/bad/WinampMediaPlayer.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.bad; 2 | 3 | /** 4 | * Now there is a need of launching new Winamp player to play audio, but playing video is not supported at this stage. 5 | * 6 | * Oops... LSP is violated here! Why? Logically winamp player only supports playing audio. So what's wrong in overriding playVideo method of super class? 7 | * 8 | * Well, see how it broke the client program (ClientTestProgram.java) 9 | * 10 | * @author tirthalp 11 | */ 12 | public class WinampMediaPlayer extends MediaPlayer { 13 | 14 | // Play video is not supported in Winamp player 15 | public void playVideo() { 16 | throw new VideoUnsupportedException(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/good/AudioMediaPlayer.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.good; 2 | 3 | /** 4 | * This class is getting ability of playing audio from its super class 5 | * 6 | * @author tirthalp 7 | */ 8 | public class AudioMediaPlayer extends MediaPlayer { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/good/ClientTestProgram.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.good; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * This is sample client program which refers MediaPlayer 8 | * 9 | * @author tirthalp 10 | */ 11 | public class ClientTestProgram { 12 | 13 | public static void main(String[] args) { 14 | 15 | // Created list of video players 16 | List allPlayers = new ArrayList(); 17 | allPlayers.add(new VlcMediaPlayer()); 18 | allPlayers.add(new DivMediaPlayer()); 19 | 20 | // Play video in all players 21 | playVideoInAllMediaPlayers(allPlayers); 22 | 23 | // Well - all works as of now...... :-) 24 | System.out.println("---------------------------"); 25 | 26 | // Now adding new Winamp player. If you uncomment below line, it would give compile time error as can't add audio player in list of video players. 27 | // allPlayers.add(new WinampMediaPlayer()); 28 | } 29 | 30 | /** 31 | * This method is playing video in all players 32 | * 33 | * @param allPlayers 34 | */ 35 | public static void playVideoInAllMediaPlayers(List allPlayers) { 36 | 37 | for(VideoMediaPlayer player : allPlayers) { 38 | player.playVideo(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/good/DivMediaPlayer.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.good; 2 | 3 | /** 4 | * Div Media player extending behavior of super class Video Media Player. Perfect, LSP is not violated here. 5 | * 6 | * @author tirthalp 7 | */ 8 | public class DivMediaPlayer extends VideoMediaPlayer { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/good/MediaPlayer.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.good; 2 | 3 | /** 4 | * Example media player super class which has ability to play audio 5 | * 6 | * @author tirthalp 7 | */ 8 | public class MediaPlayer { 9 | 10 | // Play audio implementation 11 | public void playAudio() { 12 | System.out.println("Playing audio..."); 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/good/VideoMediaPlayer.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.good; 2 | 3 | /** 4 | * This class has ability to play video as well as getting audio ability from super class 5 | * 6 | * @author tirthalp 7 | */ 8 | public class VideoMediaPlayer extends MediaPlayer { 9 | 10 | // Play video implementation 11 | public void playVideo() { 12 | System.out.println("Playing video..."); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/good/VideoUnsupportedException.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.good; 2 | 3 | public class VideoUnsupportedException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/good/VlcMediaPlayer.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.good; 2 | 3 | /** 4 | * VLC Media player extending behavior of super class Video Media Player. Perfect, LSP is not violated here. 5 | * 6 | * @author tirthalp 7 | */ 8 | public class VlcMediaPlayer extends VideoMediaPlayer { 9 | 10 | } -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/lsp/mediaplayer/good/WinampMediaPlayer.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.lsp.mediaplayer.good; 2 | 3 | /** 4 | * Now there is a need of launching new Winamp player to play audio, but playing video is not supported at this stage. 5 | * 6 | * So Winamp Media player extending behavior of super class Audio Media Player. Perfect, LSP is not violated here. 7 | * 8 | * @author tirthalp 9 | */ 10 | public class WinampMediaPlayer extends AudioMediaPlayer { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/README.md: -------------------------------------------------------------------------------- 1 | *** OCP = Open Closed Principle 2 | ----------------------------------------------- 3 | 4 | *** Description = http://www.oodesign.com/design-principles.html 5 | 6 | - "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification"; that is, such an entity can allow its behaviour to be extended without modifying its source code. 7 | 8 | - If you have a library containing a set of classes there are many reasons for which you'll prefer to extend it without changing the code 9 | that was already written (backward compatibility, regression testing...). This is why we have to make sure our modules follow Open Closed Principle. 10 | 11 | - When referring to the classes Open Close Principle can be ensured by use of Abstract classes and Concrete classes for implementing their behavior. 12 | This will enforce having Concrete Classes extending Abstract Classes instead of changing them. 13 | Some particular cases of this are Template Pattern and Strategy Pattern. 14 | 15 | 16 | ----------------------------------------------- 17 | 18 | *** Examples = 19 | 20 | (1) File Parser (package = com.tirthal.learning.oop.design.principles.clazz.solid.ocp.parsing) 21 | 22 | Requirement - Need to develop file parsing for XML and TXT types. 23 | 24 | ------ First let's see "bad" design and implementation 25 | 26 | - Refer com.tirthal.learning.oop.design.principles.clazz.solid.ocp.parsing.bad.FileParser 27 | - parse() contains if-else conditional logic to parse the file based on type 28 | - In future if you need to extend it to support CSV type, then what will you do? Well you have to change parse() to add one more condition. So OCP is violated. 29 | 30 | ------ How to do code-refactoring to make "good" design using OCP? 31 | 32 | - Refer com.tirthal.learning.oop.design.principles.clazz.solid.ocp.parsing.good.FileParser 33 | - FileParser is abstract class. Now to support new type of parsing support, just implement new class extending FileParser class. 34 | - So OCP is followed, because there is no modification in FileParser to extend new type. 35 | 36 | (2) Order Import and Export (package = com.tirthal.learning.oop.design.principles.clazz.solid.ocp.exporter) 37 | 38 | Requirement - Need to support order export in JSON and XML formats. 39 | 40 | ------ First let's see "bad" design and implementation 41 | 42 | - Refer com.tirthal.learning.oop.design.principles.clazz.solid.ocp.exporter.bad.Order 43 | - See exportAsJson() and exportAsXml() 44 | - In future if you need to extend it to support SQL export, then what will you do? Well you have to modify Order class to add exportAsSql() for SQL format. So OCP is violated. 45 | 46 | ------ How to do code-refactoring to make "good" design using OCP? 47 | 48 | - Refer com.tirthal.learning.oop.design.principles.clazz.solid.ocp.exporter.good.Order 49 | - See usage of Importer and Exporter interfaces in Order class 50 | - In future if you need to extend it to support SQL export, then what will you do? Well, just implement new SqlImporter and SqlExporter classes. 51 | - So OCP is followed, because there is no modification in Order class to extend SQL export support. 52 | 53 | (3) Drawing Shapes (package = com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing) 54 | 55 | - Reference: http://www.oodesign.com/open-close-principle.html 56 | 57 | ------- Bad design - OCP is violated (Refer GraphicEditor) 58 | 59 | - package = com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing.bad 60 | 61 | ------- Good design - OCP is followed 62 | 63 | - package = com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing.good 64 | 65 | ----------------------------------------------- 66 | 67 | Feel free to contribute code for more examples in similar fashion... :-) -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/drawing/bad/Circle.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing.bad; 2 | 3 | /** 4 | * This class indicates circle shape 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class Circle extends Shape { 10 | Circle() { 11 | super.m_type = 2; 12 | } 13 | } -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/drawing/bad/GraphicEditor.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing.bad; 2 | 3 | /** 4 | * Well, we can see here OCP is violated. 5 | * 6 | * Because if we need to extend it to support drawing square, then it requires to change drawShape() and add new drawSquare() method in this class 7 | * 8 | * @author tirthalp 9 | * 10 | */ 11 | public class GraphicEditor { 12 | 13 | /* 14 | * Draw shape as per supplied shape type 15 | */ 16 | public void drawShape(Shape s) { 17 | // If it is rectangle type, then draw rectangle 18 | if (s.m_type == 1) 19 | drawRectangle((Rectangle) s); 20 | // If it is circle type, then draw circle 21 | else if (s.m_type == 2) 22 | drawCircle((Circle) s); 23 | // Add more conditions to extend drawing other types of shapes... 24 | // Difficult to maintain numeric numbers for assigned shape types and more required testing efforts as it grows 25 | } 26 | 27 | /* 28 | * Draw circle 29 | */ 30 | private void drawCircle(Circle r) { 31 | System.out.println("Drawing Circle"); 32 | } 33 | 34 | /* 35 | * Draw rectangle 36 | */ 37 | private void drawRectangle(Rectangle r) { 38 | System.out.println("Drawing Rectangle"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/drawing/bad/GraphicEditorTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing.bad; 2 | 3 | /** 4 | * Implementation of drawing editor 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class GraphicEditorTestDrive { 10 | 11 | public static void main(String[] args) { 12 | GraphicEditor ge = new GraphicEditor(); 13 | 14 | Shape s = new Rectangle(); 15 | ge.drawShape(s); 16 | 17 | s = new Circle(); 18 | ge.drawShape(s); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/drawing/bad/Rectangle.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing.bad; 2 | 3 | /** 4 | * This class indicates rectangle shape 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class Rectangle extends Shape { 10 | Rectangle() { 11 | super.m_type = 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/drawing/bad/Shape.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing.bad; 2 | 3 | /** 4 | * This class indicates shape type 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class Shape { 10 | int m_type; 11 | } 12 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/drawing/good/Circle.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing.good; 2 | 3 | /** 4 | * Implementation of drawing circle 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class Circle extends Shape { 10 | public void draw() { 11 | System.out.println("Drawing circle"); 12 | } 13 | } -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/drawing/good/GraphicEditor.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing.good; 2 | 3 | /** 4 | * OCP is followed, as to extend functionality this class does not require to change 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class GraphicEditor { 10 | 11 | public void drawShape(Shape s) { 12 | s.draw(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/drawing/good/GraphicEditorTestDrive.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing.good; 2 | 3 | /** 4 | * Implementation of drawing editor 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class GraphicEditorTestDrive { 10 | 11 | public static void main(String[] args) { 12 | GraphicEditor ge = new GraphicEditor(); 13 | 14 | Shape s = new Rectangle(); 15 | ge.drawShape(s); 16 | 17 | s = new Circle(); 18 | ge.drawShape(s); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/drawing/good/Rectangle.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing.good; 2 | 3 | /** 4 | * Implementation of drawing rectangle 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public class Rectangle extends Shape { 10 | public void draw() { 11 | System.out.println("Drawing Rectangle"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/drawing/good/Shape.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.drawing.good; 2 | 3 | /** 4 | * Shape class which defines draw method specification without implementation 5 | * 6 | * @author tirthalp 7 | * 8 | */ 9 | public abstract class Shape { 10 | abstract void draw(); 11 | } 12 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/exporter/bad/Order.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.exporter.bad; 2 | 3 | import java.io.Writer; 4 | 5 | /** 6 | * Demo of how OCP is violated? Because to support SQL export, this class needs modification. 7 | * 8 | * @author tirthalp 9 | */ 10 | public class Order { 11 | 12 | @SuppressWarnings("unused") 13 | private int id; 14 | // + other order attributes 15 | 16 | public Order(int id) { 17 | this.id = id; 18 | } 19 | 20 | public Order(String source, Format inputFormat) { 21 | // ... logic implementation 22 | } 23 | 24 | public enum Format { JSON, XML }; // Add new formats in future 25 | 26 | public void exportAsJson(Writer out) { 27 | // ... logic implementation 28 | } 29 | 30 | public void exportAsXml(Writer out) { 31 | // ... logic implementation 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/exporter/good/JsonExporter.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.exporter.good; 2 | 3 | public class JsonExporter implements Order.Exporter { 4 | 5 | private Order order; 6 | 7 | @Override 8 | public void storeOrder(Order order) { 9 | this.order = order; 10 | 11 | // ... logic implementation 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | return "{ \"order.id\":\"" + order.getId() + "\""; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/exporter/good/JsonImporter.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.exporter.good; 2 | 3 | import java.io.Reader; 4 | 5 | public class JsonImporter implements Order.Importer { 6 | 7 | @SuppressWarnings("unused") 8 | private Reader in; 9 | 10 | public JsonImporter(Reader in) { 11 | this.in = in; 12 | } 13 | 14 | @Override 15 | public Order fetchOrderById(int id) { 16 | 17 | // ... logic implementation 18 | 19 | return new Order(123); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/exporter/good/Order.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.exporter.good; 2 | 3 | /** 4 | * Demo of how OCP is followed, because class can be extended for new export types, such as SQL export support, without 5 | * modifying this class 6 | * 7 | * @author tirthalp 8 | */ 9 | public class Order { 10 | 11 | interface Importer { 12 | Order fetchOrderById(int id); 13 | } 14 | 15 | interface Exporter { 16 | void storeOrder(Order order); 17 | } 18 | 19 | public Order(int id) { 20 | this.id = id; 21 | } 22 | 23 | public Order(Importer source) { 24 | Order o = source.fetchOrderById(id); 25 | this.id = o.id; 26 | } 27 | 28 | public void export(Exporter destination) { 29 | destination.storeOrder(this); 30 | } 31 | 32 | public int getId() { 33 | return id; 34 | } 35 | 36 | private int id; 37 | // + other order attributes 38 | } -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/exporter/good/XmlExporter.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.exporter.good; 2 | 3 | public class XmlExporter implements Order.Exporter { 4 | 5 | private Order order; 6 | 7 | @Override 8 | public void storeOrder(Order order) { 9 | this.order = order; 10 | 11 | // ... logic implementation 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | return "" + order.getId() + ""; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/exporter/good/XmlImporter.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.exporter.good; 2 | 3 | import java.io.Reader; 4 | 5 | public class XmlImporter implements Order.Importer { 6 | 7 | @SuppressWarnings("unused") 8 | private Reader in; 9 | 10 | public XmlImporter(Reader in) { 11 | this.in = in; 12 | } 13 | 14 | @Override 15 | public Order fetchOrderById(int id) { 16 | 17 | // ... logic implementation 18 | 19 | return new Order(123); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/parsing/bad/FileParser.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.parsing.bad; 2 | 3 | /** 4 | * Example file parser implementation. What's wrong? 5 | * 6 | * Well, OCP principle is violated. Why? 7 | * 8 | * In future, if there is a need to extend it for CSV Parsing, then you need to implement new method parseCSV() and change parse() to add conditional 9 | * logic. That means, more efforts to spend on code review and testing. 10 | * 11 | * @author tirthalp 12 | * 13 | */ 14 | public class FileParser { 15 | 16 | private String filePath; 17 | private String expression; 18 | 19 | public FileParser(String filePath, String expression) { 20 | this.filePath = filePath; 21 | this.expression = expression; 22 | } 23 | 24 | /** 25 | * apply parsing rule based the file based on extension type 26 | * 27 | * @param filePath 28 | * @param expression 29 | * @return 30 | */ 31 | public String parse() { 32 | 33 | if (filePath.indexOf(".xml") > 1) { // XML parsing condition 34 | 35 | return parseXML(filePath, expression); 36 | 37 | } else if (filePath.indexOf(".txt") > 1) { // TXT parsing condition 38 | 39 | return parseText(filePath, expression); 40 | 41 | } // ------- Add further conditional logic, if needs to support more type such as CSV parsing 42 | return null; 43 | } 44 | 45 | private String parseXML(String filePath, String expression) { 46 | // TODO: implement xml parsing logic using xpath 47 | return "this is parsing output of xml file"; 48 | } 49 | 50 | private String parseText(String filePath, String expression) { 51 | // TODO: implement text parsing logic using regular expression 52 | return "this is parsing output of text file"; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/ocp/parsing/good/FileParser.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.ocp.parsing.good; 2 | 3 | // NOTE - For simplicity I kept all classes in same file, but you can have separate file for each class 4 | 5 | /** 6 | * Abstract class to define parse() specification, which follows OCP. Why? 7 | * 8 | * Well if you need to extend support for more types like CSV, then you don't need to change existing class/method. Just add new class called 9 | * CsvParser extending FileParser. That means, you just need code review and testing of new CsvParser class. This is the beauty of OCP. 10 | * 11 | * @author tirthalp 12 | * 13 | */ 14 | abstract class FileParser { 15 | 16 | String filePath; 17 | String expression; 18 | 19 | public FileParser(String filePath, String expression) { 20 | this.filePath = filePath; 21 | this.expression = expression; 22 | } 23 | 24 | abstract String parse(); 25 | } 26 | 27 | /** 28 | * Implementation class for XML Parser 29 | * 30 | * @author tirthalp 31 | * 32 | */ 33 | class XMLParser extends FileParser { 34 | 35 | public XMLParser(String filePath, String expression) { 36 | super(filePath, expression); 37 | } 38 | 39 | @Override 40 | String parse() { 41 | // TODO: implement xml parsing logic using xpath 42 | return ""; 43 | } 44 | } 45 | 46 | /** 47 | * Implementation class for TXT Parser 48 | * 49 | * @author tirthalp 50 | * 51 | */ 52 | class TextParser extends FileParser { 53 | 54 | public TextParser(String filePath, String expression) { 55 | super(filePath, expression); 56 | } 57 | 58 | @Override 59 | String parse() { 60 | // TODO: implement text parsing logic using regular expression 61 | return ""; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/README.md: -------------------------------------------------------------------------------- 1 | *** SRP = Single Responsibility Principle 2 | ----------------------------------------------- 3 | 4 | *** Description = 5 | 6 | - There should never be more than one reason for a class to change. In this context a responsibility is considered to be one reason to change a class. 7 | 8 | - This principle states that if we have 2 reasons to change for a class, we have to split the functionality in two classes. 9 | Each class will handle only one responsibility and in future if we need to make one change we are going to make it in the class which handle it. 10 | 11 | - When we need to make a change in a class having more responsibilities the change might affect the other functionality of the classes. 12 | When a class has more than one responsibility, there are also more triggers and reasons to change that class. 13 | 14 | - In short if we go ahead and introduce any change to given class then the change should only be limited to that class. 15 | None of the dependent classes or consumers should have to be modified to adjust to this change. 16 | 17 | ----------------------------------------------- 18 | 19 | *** Examples = 20 | 21 | 22 | (1) Design of Modem (package = com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem) 23 | 24 | ------ First understand what can be "bad" design of Modem (why SRP is violated)? 25 | 26 | Package = com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad 27 | 28 | Problems = 29 | (1) IModem doesn't indicate clearly its responsibilities (sign of bad smell) 30 | (2) Single IModem has two responsibilities - connection management + data management. That means, it has more than one reasons to change. 31 | (3) Difficult to understand and maintain as it grows. 32 | 33 | Are you still wondering, what's problem in that??? Let's understand by code example, 34 | 35 | (1) First develop "SLOW" modem and understand code as below. 36 | - Refer IModem interface (violating SRP) 37 | - Refer ModemSlow class implements IModem interface (violating SRP) 38 | - Refer ModemSlowClient class which is consumer of ModemSlow class 39 | 40 | (2) Now understand impact, if there is a need to add "FAST" modem type. 41 | - Refer ModemFast class implements IModem interface (violating SRP) 42 | - Refer ModemFastClient class which is consumer of ModemFast class 43 | 44 | PROBLEM IS, 45 | 46 | - The connection management responsibility (dial and disconnected) is duplicated in both ModemSlow and ModemFast classes 47 | - Also in future if modem requires to dial with password logic, then it would require to change both ModemFast and ModemSlow. 48 | 49 | (3) Now just think, how can you add "SUPER FAST" modem in similar way and how more complexity will increase? 50 | 51 | 52 | ------ Now follow SRP (along with delegation principle) for "good" design of Modem: 53 | 54 | Package = com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.good 55 | 56 | Solution = 57 | 58 | (1) Follow SRP - IConnection interface is responsible for connection management. IDataChannel interface is responsible for data exchange. 59 | 60 | (2) Each interface or corresponding class is focused to single responsibility. 61 | - class ConnectionManager implements IConnection (for connection management responsibilities) 62 | - class DataChannelSlowMode implements IDataChannel (for data exchange using "SLOW" modem type) 63 | 64 | (3) Model class - implemented using Delegation design principle. 65 | 66 | (4) How does it give better control for incorporating future changes or maintenance? 67 | - Let's see how to add "FAST" modem type? We'll, just add class DataChannelFastMode which implements IDataChannel. 68 | - Also in future if modem requires to dial with password logic, then it just requires to change logic in dial() of ConnectionManager class. No impact in other classes. 69 | 70 | (5) Now just think, how can you add "SUPER FAST" type of modem in similar way? 71 | 72 | 73 | 74 | 75 | (2) Sample code is not implemented yet for below example requirement. You can try, if you really understood SRP! 76 | 77 | - Download file from given path 78 | - Apply parsing rules on given file 79 | - Store parsing output 80 | 81 | Thoughts: 82 | 83 | - Bad design by violating SRP: 84 | - Put all responsibilities in single interface and class 85 | - For example, 86 | - IDataProcessing.java (interface), FileProcessor.java (class implements IDataProcessing.java) 87 | 88 | - Better design by following SRP: 89 | - Each interface/class to focus on single responsibility and the name is enough to express its single responsibility 90 | - For example, 91 | - IDownloader.java (interface), FileDownloader.java (class implements IDownloader.java) 92 | - IParser.java (interface), CsvFileParser.java (class implements IParser.java), may be in future there can be XmlFileParser.java (class implements IParser.java) 93 | - IDataStore.java (interface), DatabaseStore (class implements IDataStore.java) 94 | 95 | ----------------------------------------------- 96 | 97 | Feel free to contribute code for more examples in similar fashion... :-) -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/bad/IModem.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad; 5 | 6 | /** 7 | * Design of ModemSlow interface. 8 | * 9 | * Why is it bad design? What's the problem? 10 | * 11 | * It has two responsibilities - Connection management + Data Management. Hence SRP is violated. 12 | * 13 | * @author tirthalp 14 | */ 15 | public interface IModem { 16 | 17 | // --- Connection management responsibilities = dial, disconnect 18 | 19 | public void dial(String phoneNumber); 20 | 21 | public void disconnect(); 22 | 23 | // --- Data management responsibilities = send, receive 24 | 25 | public void send(char c); 26 | 27 | public char receive(); 28 | } 29 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/bad/ModemFast.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad; 5 | 6 | /** 7 | * Implementation class of modem interface for "fast mode" of data send and receive. This is for design demo, so actual logic is not implemented 8 | * 9 | * @author tirthalp 10 | */ 11 | public class ModemFast implements IModem { 12 | 13 | /* 14 | * (non-Javadoc) 15 | * 16 | * @see com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad.IModem#dial(java.lang.String) 17 | */ 18 | @Override 19 | public void dial(String phoneNumber) { 20 | // TODO Auto-generated method stub 21 | System.out.println("connected successfully"); 22 | } 23 | 24 | /* 25 | * (non-Javadoc) 26 | * 27 | * @see com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad.IModem#disconnect() 28 | */ 29 | @Override 30 | public void disconnect() { 31 | // TODO Auto-generated method stub 32 | System.out.println("disconnection successfully"); 33 | } 34 | 35 | /* 36 | * (non-Javadoc) 37 | * 38 | * @see com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad.IModem#send(char) 39 | */ 40 | @Override 41 | public void send(char c) { 42 | // TODO Auto-generated method stub 43 | System.out.println("data sent successfully usign fast algorithms"); 44 | } 45 | 46 | /* 47 | * (non-Javadoc) 48 | * 49 | * @see com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad.IModem#receive() 50 | */ 51 | @Override 52 | public char receive() { 53 | // TODO Auto-generated method stub 54 | System.out.println("data received successfully using fast algorithms"); 55 | return 0; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/bad/ModemFastClient.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad; 2 | 3 | /** 4 | * This is client or consumer of ModemFast class. 5 | * 6 | * @author tirthalp 7 | */ 8 | public class ModemFastClient { 9 | 10 | public static void main(String[] args) { 11 | 12 | IModem fastModem = new ModemFast(); 13 | 14 | fastModem.dial("0000000000"); 15 | fastModem.send('t'); 16 | fastModem.receive(); 17 | fastModem.disconnect(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/bad/ModemSlow.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad; 5 | 6 | /** 7 | * Implementation class of modem interface for "slow mode" of data send and receive. This is for design demo, so actual logic is not implemented 8 | * 9 | * @author tirthalp 10 | */ 11 | public class ModemSlow implements IModem { 12 | 13 | /* 14 | * (non-Javadoc) 15 | * 16 | * @see com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad.IModem#dial(java.lang.String) 17 | */ 18 | @Override 19 | public void dial(String phoneNumber) { 20 | // TODO Auto-generated method stub 21 | System.out.println("connected successfully"); 22 | } 23 | 24 | /* 25 | * (non-Javadoc) 26 | * 27 | * @see com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad.IModem#disconnect() 28 | */ 29 | @Override 30 | public void disconnect() { 31 | // TODO Auto-generated method stub 32 | System.out.println("disconnection successfully"); 33 | } 34 | 35 | /* 36 | * (non-Javadoc) 37 | * 38 | * @see com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad.IModem#send(char) 39 | */ 40 | @Override 41 | public void send(char c) { 42 | // TODO Auto-generated method stub 43 | System.out.println("data sent successfully usign slow algorithms"); 44 | } 45 | 46 | /* 47 | * (non-Javadoc) 48 | * 49 | * @see com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad.IModem#receive() 50 | */ 51 | @Override 52 | public char receive() { 53 | // TODO Auto-generated method stub 54 | System.out.println("data received successfully using slow algorithms"); 55 | return 0; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/bad/ModemSlowClient.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.bad; 2 | 3 | /** 4 | * This is client or consumer of ModemSlow class. 5 | * 6 | * @author tirthalp 7 | */ 8 | public class ModemSlowClient { 9 | 10 | public static void main(String[] args) { 11 | 12 | IModem slowModem = new ModemSlow(); 13 | 14 | slowModem.dial("0000000000"); 15 | slowModem.send('t'); 16 | slowModem.receive(); 17 | slowModem.disconnect(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/good/ConnectionManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.good; 5 | 6 | /** 7 | * Implementation class of IConnection interface for modem's connection management. This is for design demo, so actual logic is not implemented 8 | * 9 | * @author tirthalp 10 | * 11 | */ 12 | public class ConnectionManager implements IConnection { 13 | 14 | /* 15 | * (non-Javadoc) 16 | * 17 | * @see com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.good.IConnection#dial(java.lang.String) 18 | */ 19 | @Override 20 | public void dial(String phoneNumber) { 21 | // TODO Auto-generated method stub 22 | System.out.println("connected successfully"); 23 | } 24 | 25 | /* 26 | * (non-Javadoc) 27 | * 28 | * @see com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.good.IConnection#disconnect() 29 | */ 30 | @Override 31 | public void disconnect() { 32 | // TODO Auto-generated method stub 33 | System.out.println("disconnection successfully"); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/good/DataChannelFastMode.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.good; 2 | 3 | /** 4 | * Implementation class of IDataChannel interface for "fast mode" of data send and receive. This is for design demo, so actual logic is not 5 | * implemented 6 | * 7 | * @author tirthalp 8 | * 9 | */ 10 | public class DataChannelFastMode implements IDataChannel { 11 | 12 | @Override 13 | public void send(char c) { 14 | // TODO Auto-generated method stub 15 | System.out.println("sent data using fast algorithm"); 16 | } 17 | 18 | @Override 19 | public char receive() { 20 | // TODO Auto-generated method stub 21 | System.out.println("received data using fast algorithm"); 22 | return 0; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/good/DataChannelSlowMode.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.good; 2 | 3 | /** 4 | * Implementation class of IDataChannel interface for "slow mode" of data send and receive. This is for design demo, so actual logic is not 5 | * implemented 6 | * 7 | * @author tirthalp 8 | * 9 | */ 10 | public class DataChannelSlowMode implements IDataChannel { 11 | 12 | @Override 13 | public void send(char c) { 14 | // TODO Auto-generated method stub 15 | System.out.println("sent data using slow algorithm"); 16 | } 17 | 18 | @Override 19 | public char receive() { 20 | // TODO Auto-generated method stub 21 | System.out.println("recieved data using slow algorithm"); 22 | return 0; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/good/IConnection.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.good; 5 | 6 | /** 7 | * Interface designed for connection management responsibilities of modem 8 | * 9 | * @author tirthalp 10 | * 11 | */ 12 | public interface IConnection { 13 | 14 | public void dial(String phoneNumber); 15 | 16 | public void disconnect(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/good/IDataChannel.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.good; 5 | 6 | /** 7 | * Interface designed for data management responsibilities of modem 8 | * 9 | * @author tirthalp 10 | * 11 | */ 12 | public interface IDataChannel { 13 | 14 | public void send(char c); 15 | 16 | public char receive(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/good/Modem.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.good; 2 | 3 | //If you don't know what is delegation principle, then please refer com.tirthal.learning.oop.concepts.Delegation_TestDrive 4 | /** 5 | * Modem class using Delegation design principle. 6 | * 7 | * @author tirthalp 8 | * 9 | */ 10 | public class Modem implements IConnection, IDataChannel { 11 | 12 | private IConnection connection; 13 | private IDataChannel dataChannel; 14 | 15 | public Modem(IConnection connection, IDataChannel dataChannel) { 16 | this.connection = connection; 17 | this.dataChannel = dataChannel; 18 | } 19 | 20 | @Override 21 | public void dial(String phoneNumber) { 22 | connection.dial(phoneNumber); 23 | } 24 | 25 | @Override 26 | public void disconnect() { 27 | connection.disconnect(); 28 | } 29 | 30 | @Override 31 | public void send(char c) { 32 | dataChannel.send(c); 33 | } 34 | 35 | @Override 36 | public char receive() { 37 | return dataChannel.receive(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/good/ModemFastClient.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.good; 2 | 3 | 4 | /** 5 | * @author tirthalp 6 | * 7 | */ 8 | public class ModemFastClient { 9 | 10 | public static void main(String[] args) { 11 | 12 | Modem modem = new Modem(new ConnectionManager(), new DataChannelFastMode()); 13 | 14 | modem.dial("0000000000"); 15 | modem.send('t'); 16 | modem.receive(); 17 | modem.disconnect(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /DesignPrinciples/src/com/tirthal/learning/oop/design/principles/clazz/solid/srp/modem/good/ModemSlowClient.java: -------------------------------------------------------------------------------- 1 | package com.tirthal.learning.oop.design.principles.clazz.solid.srp.modem.good; 2 | 3 | /** 4 | * @author tirthalp 5 | * 6 | */ 7 | public class ModemSlowClient { 8 | 9 | public static void main(String[] args) { 10 | 11 | Modem modem = new Modem(new ConnectionManager(), new DataChannelSlowMode()); 12 | 13 | modem.dial("0000000000"); 14 | modem.send('t'); 15 | modem.receive(); 16 | modem.disconnect(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Tirthal Patel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Learning-OOPD 2 | ============= 3 | 4 | Sample java code for learning object oriented programming design principles and patterns 5 | 6 | 7 | DesignPrinciples 8 | ----------------- 9 | 10 | For more detail, please refer [here](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPrinciples) 11 | 12 | 13 | DesignPatterns 14 | -------------- 15 | 16 | For more detail, please refer [here](https://github.com/tirthalpatel/Learning-OOPD/tree/master/DesignPatterns) --------------------------------------------------------------------------------