Decorator is a good example of OCP: open for extension, closed for modification. Looking forward to reading this book. The Head First Design Patterns book has a good chapter that covers Decorator, although it's in Java.
Great video but there is more fundamental difference between proxy and decorator than described in video: Proxy is intended to provide a surrogate or placeholder for another object to control access to it Decorator is intended to add some functionality for another object without controlling access to it According to this, there is a difference in implementation: proxy controls creation of delegate (creates by itself or obtains from dependency injection container) while constructor of decorator takes delegate as a parameter. So both LoggingProcessor and CachingProcessor are actually deocrators rather than proxies.
@@kyay10 no because you've access to underlying one from caller side: caller passes an instance of underlying processor to CacheProcessor constructor. Compare to Spring beans for example: all Spring injections you have in your bean are actually proxies and caller side never directly instantiate beans. In short: proxy tries to completely substitute and hide wrapped object while decorator is just another object with additional functionality.
Actually interesting to know: What parts of the book did you bookmark? I think sharing your tabs can be a fun thing to do and it would also help promote the book!
maybe fun interface Processor : (Request) -> Response would work better for most cases, you keep polymorphism and you get that functional look and feel
sometimes when people have problems figuring out what the decorator pattern is about, I tell them: "think about BufferedInputStream" and they are like "oh yes of course" :) (because indeed, a proxy and a decorator are so similar there's a little point to differentiate between them)
I implemented similar kind of pattern for Kafka consumer processing event, We had requirement where we need to check in inbox table for eventId before processing the event basically for duplicate check so what i did i created HOF and wrapped processEvent function in that. I hope Kotlin will have pattern matching like OCaml that this language will be rock :)
So can we say that the Filter "Pattern" or at least how FilterChains are implemented is somewhat a mix of Proxy and Decorator? Because in a Filter there is a condition that decides if the next in line will be process/called?
Would you say that Kotlin Flow and it's processing/transformation functions are a kind of a Wrapper pattern for a Type that is already implemented but for reactive programming?
Decorator/Proxy often introduce a lost of unnecessary wrappings - we can achieve the same effect without introducing these wrappers/types by simply using extension functions
Well not really I think, since the Decorator/Proxy allow to isolate the addon-behavior from the base type/interface. It means that this will allow you to compose concretions at your will later, depending on the usecase. The extension methods, on the other hand, will modify the behavior of the base type/interface for your whole project... so you can forget about composing behaviors together. Extension methods are cool, but I don't think they fit the need exposed in this video
@@FuNIpoxi They defintely fit the need. I've written up the same solution with just extension methods. No need for a pattern, wrappers, types or nesting
Extension functions can solve *some* off these needs too, but they are not design patterns. They are cool language flavors but under the hood they are just static utility functions. And it's a bit harder to properly compose them in a way presented in this wideo, especially sometimes desired non-associativity, when caching(logging(processor)) != logging(caching(processor))
@@jakubgwozdz2780 in my implement above, I've composed this as a simple list of call chains Processor().log().cache() != Processor().cache().log() It is far more elegant to properly compose than to nest everything in object My point is that you don't need this design pattern
yes I was surprised Sebastian didn't use it, but I guess it's better to focus on just one thing in the video and leave such flavours for other occasion.
Thanks Folks, What if we change it so that caller could build it like this? newRequestProcessor() .decorateWithCache() .decorateWithLogging() is that confusing?
I like that, like a builder. I guess each new decorator add an extension function to Processor? I'd prefer RequestProcessor().with(logger).with(cache) that delegates to the decorator constructors in a generic way... but no immediate ideas on how to make that happen.
Love this series ❤️
thanks!
this is cool series, with live code and more real implementation example
Love it, hope to see more of this!
Decorator is a good example of OCP: open for extension, closed for modification. Looking forward to reading this book. The Head First Design Patterns book has a good chapter that covers Decorator, although it's in Java.
유익한 내용 감사합니다. 구현하면서 생각을 따라가게 되어서 정말 좋았네요. 마지막 내용을 보니 책으로 한 번 보고 다시 또 보면 더 좋을 것 같네요
Not a big deal, but there's a small bit of audio missing at the 16 Minute mark :)
nice video and nice book, thanks for sharing!
Very interesting lesseon,
Also enjoyed the educational atmosphere of you guys interacting with the code.
Cheers!
Very good! I like this deep dive!
Great series, now I have a better idea on how we can use proxy and decorator
Great video but there is more fundamental difference between proxy and decorator than described in video:
Proxy is intended to provide a surrogate or placeholder for another object to control access to it
Decorator is intended to add some functionality for another object without controlling access to it
According to this, there is a difference in implementation: proxy controls creation of delegate (creates by itself or obtains from dependency injection container) while constructor of decorator takes delegate as a parameter.
So both LoggingProcessor and CachingProcessor are actually deocrators rather than proxies.
Isn't CacheProcessor "controlling access" to the underlying processor by not calling it sometimes?
@@kyay10 no because you've access to underlying one from caller side: caller passes an instance of underlying processor to CacheProcessor constructor.
Compare to Spring beans for example: all Spring injections you have in your bean are actually proxies and caller side never directly instantiate beans.
In short: proxy tries to completely substitute and hide wrapped object while decorator is just another object with additional functionality.
Great series 😍
@19:12 wanted to probably say the reverse. You converted proxy to decorator. Great video 🎉
Great example 💯
Great working example, love it ❤
Great explanation
Glad it was helpful!
Actually interesting to know: What parts of the book did you bookmark? I think sharing your tabs can be a fun thing to do and it would also help promote the book!
great video, would love to see more episodes from this series and maybe some functional refactoring
That's helpful, thanks!
Now for the functional version! A processor is just a `(Request) -> Response` function and decorating is just map chaining functions.
maybe fun interface Processor : (Request) -> Response would work better for most cases, you keep polymorphism and you get that functional look and feel
Now explain why a monad is like a burrito.
@@markonovakovic3838 Oh yes, fun interface really is the fun part of Kotlin
sometimes when people have problems figuring out what the decorator pattern is about, I tell them: "think about BufferedInputStream" and they are like "oh yes of course" :) (because indeed, a proxy and a decorator are so similar there's a little point to differentiate between them)
Thank you so much buddy i digg whole youtube for this but you are the only one ❤️🔥
This is simply. Awesome
great examples. thanks!
Do you have a Playlist about it?
very much your efforts to help us noobs out.
I implemented similar kind of pattern for Kafka consumer processing event, We had requirement where we need to check in inbox table for eventId before processing the event basically for duplicate check so what i did i created HOF and wrapped processEvent function in that. I hope Kotlin will have pattern matching like OCaml that this language will be rock :)
So can we say that the Filter "Pattern" or at least how FilterChains are implemented is somewhat a mix of Proxy and Decorator? Because in a Filter there is a condition that decides if the next in line will be process/called?
Would you say that Kotlin Flow and it's processing/transformation functions are a kind of a Wrapper pattern for a Type that is already implemented but for reactive programming?
Decorator/Proxy often introduce a lost of unnecessary wrappings - we can achieve the same effect without introducing these wrappers/types by simply using extension functions
Well not really I think, since the Decorator/Proxy allow to isolate the addon-behavior from the base type/interface. It means that this will allow you to compose concretions at your will later, depending on the usecase. The extension methods, on the other hand, will modify the behavior of the base type/interface for your whole project... so you can forget about composing behaviors together.
Extension methods are cool, but I don't think they fit the need exposed in this video
@@FuNIpoxi They defintely fit the need. I've written up the same solution with just extension methods. No need for a pattern, wrappers, types or nesting
my gh tag is xxfast
Extension functions can solve *some* off these needs too, but they are not design patterns. They are cool language flavors but under the hood they are just static utility functions. And it's a bit harder to properly compose them in a way presented in this wideo, especially sometimes desired non-associativity, when caching(logging(processor)) != logging(caching(processor))
@@jakubgwozdz2780 in my implement above, I've composed this as a simple list of call chains
Processor().log().cache() != Processor().cache().log()
It is far more elegant to properly compose than to nest everything in object
My point is that you don't need this design pattern
Packtpub redirects print purchases to Amazon ☹️
How I wish I can write code they way you people do
ty for video
I think this should be called "middleware pattern"?
works gj
Ok
It shouldn't be called Decorator or Wrapper, it should be called an around advice. Only half joking.
way too many cuts in between sentences. Kills the video's flow and made me quit after the first few minutes.
Out of interest: the caching can be a simple one liner,no?
return cache.getOrPut(request) { processor.process(request) }
Yep, or Seb could've used cache.get(request) ?: processor.process(request).also { cache.put(request, it) }
yes I was surprised Sebastian didn't use it, but I guess it's better to focus on just one thing in the video and leave such flavours for other occasion.
There were quite a few lines of code that could be simplified, but that was out of scope for the video
Thanks Folks, What if we change it so that caller could build it like this?
newRequestProcessor()
.decorateWithCache()
.decorateWithLogging()
is that confusing?
drop the "new" and "decorate" and it's clear and readable :)
I like that, like a builder. I guess each new decorator add an extension function to Processor? I'd prefer RequestProcessor().with(logger).with(cache) that delegates to the decorator constructors in a generic way... but no immediate ideas on how to make that happen.