Nice to listen to the experienced people. Just have read book about design pattern and i would be very happy to see more episodes about them. Thanks guys.
Not sure how others think about this (so please comment what you think), but I think there is more to the Factory Method (or Factory Function / Factory Lambda) pattern than just the use some method/function/lambda to map one type to another. I think what's part of the classical pattern, which is missing here, is that you declare an abstract (possibly default) function in some super entity, e.g. an interface. E.g. `interface GameLoader { fun loadGame(notation: List): List }`. That really lets you vary the `GameLoader` implementation at the call site, without the call site changing. Just having some top-level function mapping strings to pieces isn't really the classical Factory Function pattern, right? That's like calling a type alias equivalent to a type defined from a class or interface. Simply because the signature matches of a random different function that maps strings to pieces, it doesn't mean that it is a Factory Function pattern, because you can plug it in at the call site. There might be different use cases for mapping strings to pieces that do not load a game. Likewise, defining it in the companion object of the source or target type, or just as an extension, is equally flawed: there is no way to vary implementations of the function without actually using the classical pattern, where some interface/super class declared the Factory Function. So: consider wrapping the function in some interface an implementing different variants as implementations. Yes, I know: that is introducing classic OOP boilerplate. But it _does_ provide the type safety that the implementor _must_ inherit from `GameLoader` and that you can only use `GameLoader` instances throughout your code. That is completely omitted in this video. What do you think about that? I do agree that the Static Factory Function (mentioned in the video) is a simpler version of the Factory Function, but they're not the same.
Thank you for the thoughtful comment. TH-cam comments section is not the best place to discuss code concepts, but I'll do my best. I agree with your points, this implementation does have its tradeoffs compared to the classical implementation that you describe. You may need that extra level of abstraction if you design a library, and especially if you plan that users of the library may need to extend it. But it would be very hard to encompass all those nuances in a video, without confusing anyone. And I do think that a more pragmatic approach for Design Patterns is beneficial for most of the Kotlin applications.
@@alexeysoshin8442 Have to agree with Eric. The example you've provided in the video and in the book is a factory (or simple factory) pattern, not factory method. Factory method implies that you can override construction logic somewhere.
very nice intro to thinkings on factory methods. I very much liked the iteration to the final method. Just enough on items to point out nicities of Kotlin. Thanks.
The extension function is fantastic to implement the static factory pattern when you don't want the Piece class to have knowledge of more complex classes or you want to separate the application module into "layers" and you want a piece out of a class that doesn't belong to ita layer
Shouldn't it be drop(1) instead of drop(0)? And, do you think the following produces the same result as the first two statements of the method? val pieceType = name.first() val position = name.substring(1)
depends ; sometimes you really dont want to overengineer things. In the case of sealed classes/interfaces, you know no other implementations will exist, and those will generally be extremely simple POJOs/data classes. With that in mind, this allows for generally unsafe patterns to become safe, such as pattern matching / safe when casts, or what you see in this video.
I bought your book, but I am little confused. You describe "builder" pattern, but it isn't a real builder pattern. It is just simple "assembler", without any concrete builders or engineer. There wasn't event any mention, that it is simplified version that is called "builder" by java community. If anyone plans to buy this - it is not bad, but it will be better to just stick with original Design Patterns, and translate those patterns to Kotlin yourself
By fake constructor, do you mean operator fun invoke on companions? I like that style when there's a "copy constructor" (the real constructor, declaring properties) and one "convenience constructor" (the factory method) because the intent and IDE hints are cleaner. For multiple factory methods I like to name them.
The example is a "factory" of some sort, but it misses the mark on the topic a bit. To me, a factory is an interface my code receives from the caller, and it abstracts away the creation of an object. I don't know the concrete class, but I do know the interface it implements, and the factory builds it for me. In the chess example, it would mean that the individual implementations of "Piece" were unknown within "fromNotation", and it would receive the notation as well as an interface that maps a piece letter to a corresponding object that implements Piece.
You could talk also about some other structural patterns (abstract factory or factory method ..), also i'am not a fan of using the static factory method in the Piece itself, we should separate the creation of the system from using it, imagine another team wants only the piece, why they will take also the the factory Nice video thank you, waiting for the next one !
# I wrote a version with sealed interface and data class val notation = listOf("pa3","qc5") fun main() { val gameState = notation.map { Piece.fromNotation(it) } println(gameState) } sealed interface Piece { val position: String companion object { fun fromNotation(piece: String): Piece { val pieceType = piece[0] val position = piece.substring(1) return when (pieceType) { 'p' -> Pawn(position) 'q' -> Queen(position) else -> error("Unknown piece!") } } } } data class Pawn(override val position:String): Piece data class Queen(override val position:String): Piece
Really enjoyed the episode! Would like to see more of such episodes on patters. That's useful!
Enjoyed this more than I initially expected. Nicely done and edited. Thanks for uploading!
Really enjoyed the episode! Would like to see more of such episodes with coding and discussion over it.
Nice to listen to the experienced people. Just have read book about design pattern and i would be very happy to see more episodes about them. Thanks guys.
Great episode! The transition to abstract factory was masterful. More please 😊
Nice one - I’d love to see more on design patterns on this channel. Great topic for a series / playlist.
Thanks for this kind of videos, pure gold
Hope to see more of this
Not sure how others think about this (so please comment what you think), but I think there is more to the Factory Method (or Factory Function / Factory Lambda) pattern than just the use some method/function/lambda to map one type to another. I think what's part of the classical pattern, which is missing here, is that you declare an abstract (possibly default) function in some super entity, e.g. an interface. E.g. `interface GameLoader { fun loadGame(notation: List): List }`. That really lets you vary the `GameLoader` implementation at the call site, without the call site changing. Just having some top-level function mapping strings to pieces isn't really the classical Factory Function pattern, right? That's like calling a type alias equivalent to a type defined from a class or interface. Simply because the signature matches of a random different function that maps strings to pieces, it doesn't mean that it is a Factory Function pattern, because you can plug it in at the call site. There might be different use cases for mapping strings to pieces that do not load a game. Likewise, defining it in the companion object of the source or target type, or just as an extension, is equally flawed: there is no way to vary implementations of the function without actually using the classical pattern, where some interface/super class declared the Factory Function.
So: consider wrapping the function in some interface an implementing different variants as implementations. Yes, I know: that is introducing classic OOP boilerplate. But it _does_ provide the type safety that the implementor _must_ inherit from `GameLoader` and that you can only use `GameLoader` instances throughout your code. That is completely omitted in this video. What do you think about that?
I do agree that the Static Factory Function (mentioned in the video) is a simpler version of the Factory Function, but they're not the same.
Thank you for the thoughtful comment.
TH-cam comments section is not the best place to discuss code concepts, but I'll do my best.
I agree with your points, this implementation does have its tradeoffs compared to the classical implementation that you describe.
You may need that extra level of abstraction if you design a library, and especially if you plan that users of the library may need to extend it.
But it would be very hard to encompass all those nuances in a video, without confusing anyone. And I do think that a more pragmatic approach for Design Patterns is beneficial for most of the Kotlin applications.
@@alexeysoshin8442 Have to agree with Eric. The example you've provided in the video and in the book is a factory (or simple factory) pattern, not factory method. Factory method implies that you can override construction logic somewhere.
very nice intro to thinkings on factory methods. I very much liked the iteration to the final method. Just enough on items to point out nicities of Kotlin. Thanks.
The extension function is fantastic to implement the static factory pattern when you don't want the Piece class to have knowledge of more complex classes or you want to separate the application module into "layers" and you want a piece out of a class that doesn't belong to ita layer
Good Professor Bruegge. I did also very enjoy his lecture.
Good job guys! Great content!
Awesome epsiode as usual
Interesting take on if-else vs when. I only use if-else when it fits in a one-line expression, otherwise I go the when route.
Can you do the builder pattren next pleaaase
Thank you for this.
Nice talk as usual.
Shouldn't it be drop(1) instead of drop(0)?
And, do you think the following produces the same result as the first two statements of the method?
val pieceType = name.first()
val position = name.substring(1)
ya you are right drop calls substring and substring takes beginIndex inclusive
Love to see one on the visitors patter
is there playlist contain all Alexey episode?
Superclasses shouldn't know about subtypes though. Does it being sealed change things? How about it being in the companion?
depends ; sometimes you really dont want to overengineer things.
In the case of sealed classes/interfaces, you know no other implementations will exist, and those will generally be extremely simple POJOs/data classes. With that in mind, this allows for generally unsafe patterns to become safe, such as pattern matching / safe when casts, or what you see in this video.
operator fun invoke(notation: String): Piece
love you guys I really like this episode
Dialog - excelent way to teach.
I bought your book, but I am little confused. You describe "builder" pattern, but it isn't a real builder pattern. It is just simple "assembler", without any concrete builders or engineer. There wasn't event any mention, that it is simplified version that is called "builder" by java community. If anyone plans to buy this - it is not bad, but it will be better to just stick with original Design Patterns, and translate those patterns to Kotlin yourself
"We all are Chinese rooms." Thank you, now I know it's OK to feel this way sometimes! :)
I really enjoyed it. 🌟
What are the use cases of fake constructors? They also serve as factory methods.
By fake constructor, do you mean operator fun invoke on companions? I like that style when there's a "copy constructor" (the real constructor, declaring properties) and one "convenience constructor" (the factory method) because the intent and IDE hints are cleaner. For multiple factory methods I like to name them.
Greate episode
The example is a "factory" of some sort, but it misses the mark on the topic a bit. To me, a factory is an interface my code receives from the caller, and it abstracts away the creation of an object. I don't know the concrete class, but I do know the interface it implements, and the factory builds it for me. In the chess example, it would mean that the individual implementations of "Piece" were unknown within "fromNotation", and it would receive the notation as well as an interface that maps a piece letter to a corresponding object that implements Piece.
Thanks
Quotes of great men: "Kotlin is easier than Scala, more type safety than Groovy and more fun than Java." 😁
You could talk also about some other structural patterns (abstract factory or factory method ..), also i'am not a fan of using the static factory method in the Piece itself, we should separate the creation of the system from using it, imagine another team wants only the piece, why they will take also the the factory
Nice video thank you, waiting for the next one !
Nice
хахах, красавчик)
10:55 JEP 427 goes brr
# I wrote a version with sealed interface and data class
val notation = listOf("pa3","qc5")
fun main() {
val gameState = notation.map { Piece.fromNotation(it) }
println(gameState)
}
sealed interface Piece {
val position: String
companion object {
fun fromNotation(piece: String): Piece {
val pieceType = piece[0]
val position = piece.substring(1)
return when (pieceType) {
'p' -> Pawn(position)
'q' -> Queen(position)
else -> error("Unknown piece!")
}
}
}
}
data class Pawn(override val position:String): Piece
data class Queen(override val position:String): Piece
You are looking like indian actor(saif ali khan) 😁😊😊
woah you look like steve jobs