All Projects → CloudCoders → Design-Patterns

CloudCoders / Design-Patterns

Licence: other
Project for learning and discuss about design patterns

Programming Languages

kotlin
9241 projects

Projects that are alternatives of or similar to Design-Patterns

Designpatternslibrary
A comprehensive design patterns library implemented in C#, which covers various design patterns from the most commonly used ones to the lesser-known ones. Get familiar with and learn design patterns through moderately realistic examples.
Stars: ✭ 485 (+2931.25%)
Mutual labels:  oop, design-patterns
Design Patterns Php
Most simplest design pattern implementation in PHP, including all 23 GoF patterns plus some other patterns
Stars: ✭ 85 (+431.25%)
Mutual labels:  oop, design-patterns
Java design patterns
Java 实现的面向对象设计模式示例, 创建者、抽象工厂、工厂方法、原型、单例、适配器、桥接、组合、装饰器、备忘录、观察者、状态、策略、模板方法、访问者
Stars: ✭ 547 (+3318.75%)
Mutual labels:  oop, design-patterns
Stampit
OOP is better with stamps: Composable object factories.
Stars: ✭ 3,021 (+18781.25%)
Mutual labels:  oop, object-oriented
Learning Oop In Php
A collection of resources to learn object-oriented programming and related concepts for PHP developers.
Stars: ✭ 2,359 (+14643.75%)
Mutual labels:  oop, design-patterns
Design Patterns
Contains examples of design patterns that implemented in php
Stars: ✭ 375 (+2243.75%)
Mutual labels:  oop, design-patterns
Designpatterns
DesignPatterns samples by csharp on dotnetcore 《大话设计模式》 中设计模式总结/C#(.NETCore)代码
Stars: ✭ 73 (+356.25%)
Mutual labels:  oop, design-patterns
design-patterns
Simple examples of Design Patterns with PHP Examples
Stars: ✭ 75 (+368.75%)
Mutual labels:  oop, design-patterns
Frontend Hard Mode Interview
《前端内参》,有关于JavaScript、编程范式、设计模式、软件开发的艺术等大前端范畴内的知识分享,旨在帮助前端工程师们夯实技术基础以通过一线互联网企业技术面试。
Stars: ✭ 2,338 (+14512.5%)
Mutual labels:  oop, fp
Nest Cnode
CNode 社区 Nest 版本 https://cnodejs.org/
Stars: ✭ 125 (+681.25%)
Mutual labels:  oop, fp
design-patterns-java
📗 Classic OOP Design Patterns from GoF, implemented in Java.
Stars: ✭ 25 (+56.25%)
Mutual labels:  oop, design-patterns
Lw oopc
modified from http://sourceforge.net/projects/lwoopc/
Stars: ✭ 159 (+893.75%)
Mutual labels:  oop, object-oriented
BashClass
BashClass is an Object Oriented Programming language that compiles to BASH 4.4
Stars: ✭ 40 (+150%)
Mutual labels:  oop, object-oriented
Designpatternsphp
sample code for several design patterns in PHP 8
Stars: ✭ 20,158 (+125887.5%)
Mutual labels:  oop, design-patterns
alleycat-reactive
A simple Python library to provide an API to implement the Reactive Object Pattern (ROP).
Stars: ✭ 15 (-6.25%)
Mutual labels:  oop, fp
Solrb
Solr + Ruby + OOP + ❤️ = Solrb
Stars: ✭ 37 (+131.25%)
Mutual labels:  oop, object-oriented
Front-End-Design-Patterns
Design Patterns
Stars: ✭ 25 (+56.25%)
Mutual labels:  oop, design-patterns
estore
Electronic Store Application - A web based application developed using PHP and Driven by MySQL Database
Stars: ✭ 48 (+200%)
Mutual labels:  oop, design-patterns
Low Level Design Primer
Dedicated Resources for the Low-Level System Design. Learn how to design and implement large-scale systems. Prep for the system design interview.
Stars: ✭ 2,706 (+16812.5%)
Mutual labels:  oop, design-patterns
Interviews
A list of fancy questions I've been asked during the interviews I had. Some of them I ask when interviewing people.
Stars: ✭ 140 (+775%)
Mutual labels:  oop, fp

Kotlin OOP and FP Design Patterns

Build Status Kotlin version badge

Index

Object oriented paradigm

Behavioral

Chain of Responsability

It avoids coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. It pass the request along the chain until an object handles it.

This pattern is usually used within a Composite

Example

interface MessageProcessor {
  fun process(message: Message): String
}

class UsernameProcessor(val next: MessageProcessor? = null): MessageProcessor {
  override fun process(message: Message): String = when (message) {
    is Message.Username -> message.message.toUpperCase()
    else -> next?.process(message) ?: message.message
  }
}

class PasswordProcessor(val next: MessageProcessor? = null): MessageProcessor {
  override fun process(message: Message): String = when (message) {
    is Message.Password -> message.message.map { '*' }.joinToString(separator = "")
    else -> next?.process(message) ?: message.message
  }
}

class PlainTextProcessor(val next: MessageProcessor? = null): MessageProcessor {
  override fun process(message: Message): String = when (message) {
    is Message.PlainText -> message.message
    else -> next?.process(message) ?: message.message
  }
}

Usage

object ProcessingComposite : MessageProcessor {
  val bottom = PlainTextProcessor()
  val next = PasswordProcessor(bottom)
  val usernameProcessor = UsernameProcessor(next)
  
  override fun process(message: Message): String = usernameProcessor.process(message)
}

val password = Message.Password("SuperSecret")
val username = Message.Username("@Cotel")

println(ProcessingComposite.process(password))    // "***********"
println(ProcessingComposite.process(username))    // "@COTEL"

Command

It is an object-oriented callback. Encapsulates a request as an object. It decouples the object that invokes the operation from the one that knows how to perform it.

Example

interface Command {
  fun matches(command: String): Boolean
  fun execute()
}

class ChooseNoodlesCommand(val cart: Cart) : Command {
  companion object {
    val CHOOSE_NOODLES : String = "1"
  }
  
  override fun matches(command: String): Boolean = command == CHOOSE_NOODLES
  
  override fun execute() {
    cart.chooseNoodles()
  }
}

class Processor(val commands: List<Command>,
                val help: Command) {
                
  fun process(command: String): Command = 
    commands.filter { it.matches(command) }.getOrElse(0) { help } 
    
}

Usage

val scanner = Scanner(System.`in`)
val cart = Cart(scanner)
val commands = listOf(
  ChooseNoodlesCommand(cart),
  // ...
)
val proc = Proccessor(commands, CommandNotFound())

var commandChoice = -1
do {

  commandChoice = scanner.nextInt()
  proc.proccess("$commandChoice").execute()
  
} while (commandChoice != 0)

Interpreter

Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language

In progress

Iterator

It provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation

Example

interface Iterator<T> {
  fun next(): T?
  fun prev(): T?
  fun set(element: T)
  fun get(): T
}

interface Iterable<T> {
  fun getIterator(): Iterator<T>
}

class NormalIterator<T>(private val list: MutableList<T>) : Iterator<T> {
  private var index = 0

  override fun next(): T? = if (hasNext()) list[index++] else throw NoSuchElementException()
  override fun previous(): T? = if (hasPrev()) list[index--] else throw NoSuchElementException()

  override fun get(): T = list[index]
  override fun set(element: T) {
    list[index] = element
  }
}

Usage

val list = mutableListOf(10, 1, 12, 4)
val iterator = NormalIterator(list)

iterator.next()
iterator.next()
iterator.prev()
iterator.get() // 1

Mediator

Define an object that encapsulates how a set of objects interact. It designs an intermediary to decouple many peers.

In progress

Memento

It captures and externalizes an object's internal state so it can get back to this state later without violating encapsulation

In progress

Null Object

It encapsulates the absence of an object by providing an alternative that offers suitable default behaviour for doing nothing. Useful to abstract the handling of null away from the client

In progress

Observer

It defines a one-to-many dependency between object so that when one changes its state, all its dependents are notified and updated automatically.

In Kotlin, this pattern is extremely easy to implement thanks to property delegation

Example

interface Observer<in T> {
  fun onValueChange(newValue: T, oldValue: T)
}

class CustomersObserver : Observer<Int> {
  override fun onValueChange(newValue: Int, oldValue: Int) = when {
    newValue > oldValue -> println("A new customer entered. Current customers $newValue")
    else -> println("A customer left. Current customers: $newValue")
  }
}

class Shop(private val observer: Observer<Int>) {
  var currentCustomers by Delegates.observable(0) { _, old, new ->
    observer.onValueChange(new, old)
  }
}

Usage

shop.currentCustomers++ // prints "A new customer entered ..."
shop.currentCustomers-- // prints "A customer left ..."

State

It allows an object to alter its behaviour when its internal state changes.

We can use Kotlin's sealed classes to define a restricted hierarchy so that the current State can only have limited values from a set.

Example

interface State {
  fun next(): State
}

sealed class SemaphoreStates : State {
  object Red : SemaphoreStates() {
    override fun next() = Green
  }

  object Green : SemaphoreStates() {
    override fun next() = Yellow
  }

  object Yellow : SemaphoreStates() {
    override fun next() = Red
  }
}

class Semaphore(startingState: State = SemaphoreStates.Red) {
  var state = startingState
    private set

  fun nextLight() {
    state = state.next()
  }
}

Usage

fun Semaphore.canICross() = this.state is SemaphoreStates.Green 

val semaphore = Semaphore()

println(semaphore.canICross()) // false

semaphore.nextLight()

println(semaphore.canICross()) // true

Strategy

Define a family of algorithms, encapsulate each one, and make them interchangeable. It captures the abstraction in an interface and buries implementation details in derived classes.

In Kotlin, we can implement this pattern with only functions because of the support for first order functions.

Example

val GeneralStrategy : (Double) -> Double = { it + it * 0.21 }

val ReducedStrategy : (Double) -> Double = { it + it * 0.10 }

val SuperReducedStrategy = { cost: Double -> cost + cost * 0.04 } // Alternative way to define it

Usage

var ivaStrategy = GeneralStrategy  // You can change the strategy in execution time
val price = 3.14

println(ivaStrategy(price))

Template

Define an skeleton of an algorithm in an operation, deferring some steps to client subclasses. These subclasses can redefine certain steps of an algorightm without changing its structure

In progress

Visitor

Represent an operation to be performed on the elements of an object structure. It lets you define a new operation without changing the classes of the elements on which it operates.

In progress

Creational

Abstract Factory

It provides an interface for creating families of related dependents objects without specifying their concrete classes

In progress

Builder

It separates the construction of a complex object from its representation so that the same construction process can create different representations.

In progress

Factory

It defines an interface for creating an object, but let subclasses decide which class to instantiate.

Example

class NoodlesFactory {
  fun getNoodles(noodleType: Int): Noodles {
    when (noodleType) {
      1 -> return EggNoodles()
      2 -> return UdonNoodles()
      3 -> return WheatNoodles()
      else -> throw NoNoodlesMatchException()
    }
  }
}

Usage

val scanner = Scanner(System.`in`)
val noodlesFactory = NoodlesFactory()

val noodlesType = scanner.nextInt()
val noodles = noodlesFactory.getNoodles(noodlesType)

Object Pool

An Object Pool can offer a significant performance boost, it is most effective in situations where the cost of initializing a class instance is high.

In progress

Prototype

It specifies the kind of objects to create using a prototypical instance and create new objects by copying this instance.

In progress

Singleton

It ensures a class has only one instance and provide a global point of access to it.

In Kotlin we can make use of the reserved keyword Object

Example

object OneInstance {

  fun sayHello() = println("Hello")

}

Usage

OneInstance.sayHello()

Structural

Adapter

It converts an interface of a class into another interface clients expect. It lets classes work together that couldn't otherwise.

Example

We're going to adapt a U.S robot interface that uses miles per hour and feet (Imperial system) to a European interface that employs Km/h and meters (Metric system).

interface USRobotsAdaptee{
  var speedInMilesPerHour: Double
  fun enableFirstLawMode()
  fun jump(feet: Double)
}

interface EuropeanRobotTarget
{
  var speedInKilometersPerHour: Double
  fun jump(meters: Double)
}

class USRobot(override var speedInMilesPerHour: Double = 0.0) :USRobotsAdaptee{
  override fun enableFirstLawMode() {
    println("Partial first law enabled")
  }

  override fun jump(feet: Double) {
    println("JUMPED $feet feet")

  }
  
data class EURobotAdapter(var usRobot: USRobot) : EuropeanRobotTarget{
  override var speedInKilometersPerHour: Double
    get() = usRobot.speedInMilesPerHour * 1.6093
    set(value) {usRobot.speedInMilesPerHour = value * 0.62137}



  override fun jump(meters: Double) {
    usRobot.jump(meters * 0.3048)
  }

Usage

val euRobot = EURobotAdapter(USRobot())
euRobot.speedInKilometersPerHour = 3.4

println("Current speed in KM/h: ${euRobot.speedInKilometersPerHour}")
euRobot.jump(12.5)

Bridge

It decouples an abstraction from its implementation so that the two can vary independently.

In progress

Composite

Compose objects into tress structures to represent whole-part hierarchies. It lets clients treat individual objects and compositions uniformly.

Example

interface Cooker {
  fun cook()
}

interface ChineseCooker(private val cookers: MutableList<Cooker> = mutableListOf()): Cooker {
  fun add(cooker: Cooker) = cookers.add(cooker)
  
  override fun cook() {
    println("Cooking plate with soy sauce")
    cookers.forEach(Cooker::cook)
  }
}

interface DeepFryer(): Cooker {
  override fun cook() {
    println("And frying")
  }
}

class Kitchen(private val cookers: MutableList<Cooker> = mutableListOf()): Cooker {
  fun add(cooker: Cooker) {
    cookers.add(cooker)
  }
  
  fun remove(cooker: Cooker) {
    cookers.remove(cooker)
  }
  
  override fun cook() {
    cookers.forEach(Cooker::cook)
  }
}

Usage

val chinese = ChineseCooker()
chinese.add(DeepFryer())

val cookers = mutableListOf(chinese)
val kitchen = Kitchen(cookers)
kitchen.cook()

Decorator

It attachs additional responsabilities to an object dynamically.

In Kotlin, we don't need to redefine the methods of the decorated interface. We can use by to delegate those methods to the decorated class.

Example

interface Noodles {
  fun calculateCost(): Double
}

class UdonNoodles : Noodles {
  override fun calculateCost() = 3.50
}

abstract class SauceDecorator(private val noodles: Noodles): Noodles by noodles {
  abstract val SPICINESS: Int
}

class RedPepperSauce(noodles: Noodles): SauceDecorator(noodles) {
  override val SPICINESS: Int = 3
}

Usage

val udonNoodles = UdonNoodles()
val udonNoodlesWithRedPepperSauce = RedPepperSauce(udonNoodles)

println(udonNoodlesWithRedPepperSauce.calculateCost()) // 3.50
println(udonNoodlesWithRedPepperSauce.SPICINESS) // 3

Facade

It provides a unified interface to a set of interfaces in a subsystem.

Example

class NetInvoiceSalaryFacade(val iva: IVAOperation = IVAOperation(),
                             val irpf: IRPFOperation = IRPFOperation()) {
  fun calculate(salary: Double): Double =
    salary + iva.apply(salary) - irpf.apply(salary)
    
  fun calculateAnnual(monthlySalary: Double): Double = 
    calculate(monthlySalary * 12)
}

class IVAOperation {
  fun apply(amount: Double): Double = amount + (amount * 0.21)
}

class IRPFOperation {
  fun apply(amount: Double): Double = amount + (amount * 0.15)
}

Usage

val facade = NetInvoiceSalaryFacade()
println(facade.calculateAnnual(1000))

Flyweight

It uses sharing to support large numbers of fine-grained objects efficiently

In progress

Proxy

It provides a placeholder for another object to control access to it. It is an extra level of indirection to support controlled or intelligent access.

There are 3 types of Proxies

  • Protection Proxy - Which control the access to an object.
  • Virtual Proxy - Which prevents creating an object until it is really necessary to save resources.
  • Remote Proxy - Which duty is to create a correct request to ask a remote real object which may not be in our domain.

Protection proxy

Example

class Transaction(val amount: Double,
                  val isInternational: Boolean)

interface Payment {
  fun pay(transaction: Transaction)
}

class PaymentProtectionProxy(private val payment: Payment): Payment {
  override fun pay(transaction: Transaction) {
    if (transaction.isInternational) println("Payment is international, we do not allow it")
    else payment.pay(transaction)
  }
}

class RealPayment(val initialAmount: Double): Payment {
  override fun pay(transaction: Transaction) {
    initialAmount -= transaction.amount
    println("Successful!")
  }
}

Usage

val account = RealPayment(100.0)
val localBank = PaymentProtectionProxy(account)

localBank.pay(Transaction(3.15, true)) // It won't allow us to pay
localBank.pay(Transaction(3.15, false)) // It will work

Virtual Proxy

We can use kotlin's lazy delegation

Example

interface Screen {
  fun show()
}

class VirtualScreen(val screenCreation: () -> Screen) : Screen {
  private val realScreen: Screen by lazy {
    screenCreation()
  }
  
  override fun show() {
    realScreen.show()
  }
}

class RealScreen : Screen {
  constructor() {
    // It gets really hungry in here
  }
  
  override fun show() {
    println("¯\_(ツ)_/¯")
  }
}

Usage

val virtualScreen = VirtualScreen({ RealScreen() })  // We haven't created a RealScreen yet

// Several lines after...

virtualScreen.show()  // RealScreen is needed now, so we create it

Remote Proxy

Example

// Client code

interface Message {
  fun writeInChannel(text: String, channel: String)
}

class MessageProxy(private val outpuStream: OutputStream) : Message {
  override fun writeInChannel(text: String, channel: String) {
    outpuStream.write("Headers:$text:$channel:Goodbye")
  }
}

// Server code

class ServerMessage(val channels: List<Channel>) : Message {
  override fun writeInChannel(text: String, channel: String) {
    channels.forEach {
      if (it == channel) {
        println("$text")
      }
    }
  }
}

class Server {
  val channels = listOf("1", "2", "3")
  val messageHandler = ServerMessage(channels)
  
  fun onClientMessage(request: String) {
    val (message, channel) = request
      .removePrefix("Headers:")
      .removeSuffix(":Goodbye")
      .split(":")
      
    messageHandler.writeInChannel(message, channel)                  
  }
}

Functional paradigm

Monads

Option AKA Maybe

It represents a value which is of type A or none.

Example

sealed class Maybe<A> {
  companion object {
    fun <A: Any> fromNullable(a: A?): Maybe<A> = if (a != null) Maybe.Just(a) else Maybe.None
  }
  
  abstract val isEmpty: Boolean
  
  fun <B> fold(ifEmpty: () -> B, fn: (A) -> B): B = when (this) {
    is Maybe.None -> ifEmpty()
    is Maybe.Just -> fn(value)
  }
}

fun <B> Maybe<B>.getOrElse(default: () -> B): B = fold({ default() }, { it })

Usage

val returnExplanatoryString: () -> String = { "Result is null" }
val listOfCountries = listOf("Spain", "France", "Italy")
val getValueInList: (String) -> (List<String>) -> String? = { item -> 
  {
    list -> list.find { it == item }
  }
}
val getTanzaniaInList = getValueInList("Tanzania")

val maybeTanzania = Maybe.fromNullable(getTanzaniaInList(listOfCountries))

val country = maybeTanzania
  .map(String::toUpperCase)
  .getOrElse(returnExplanatoryString)
val countryClassic = listOfCountries.find { it == "Tanzania" }?.toUpperCase()

println(country)        // This won't be null
println(countryClassic) // This can be null
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].