+ 8

Difference generics - abstract base class

Hello. I am trying to do the following: Write a program that does different string encryption. I want to use a builder pattern, so that I can extend the program with more encryption schemes. There will be a "context" class that does the string adding and such but does not know how to encrypt. That is extended by the concrete encryption class that comes from the builder (if I understand that correctly, that is called a "strategy pattern"). Attached is a code that should give you an idea of how it will look like. the question I have is the difference in the two "Context" classes - one is generic, the other uses an abstract type. To me, it seems generics only make things more complicated, but maybe there is something that I don't know about. It would be helpful if someone could point out the differences, and which approach I should choose (and why). Thank you! Here is the code: https://code.sololearn.com/c1ix8UMbZsbE

15th Sep 2021, 3:06 PM
Agnes Ahlberg
Agnes Ahlberg - avatar
25 Rรฉponses
+ 9
Agnes Ahlberg I commend you for challenging your understanding to dig deeper. I love these discussions, especially as a seasoned software architect. The challenge in learning these concepts is not having use case examples to demonstrate when these design patterns make sense and when they are being forced. I wish I wasn't so busy these days. Otherwise, I could spend some time talking through the issues with the approach here.
18th Sep 2021, 8:49 PM
David Carroll
David Carroll - avatar
+ 9
Kiwwi# Generics used in tandem with interfaces make for a powerful combination. It's really hard to describe on simple examples. I think you might be working from a narrow view of generics or maybe one that was over complicated. Generics should make code much simpler, not the opposite. I have to believe you've been looking at some poorly implemented examples.
19th Sep 2021, 5:56 AM
David Carroll
David Carroll - avatar
+ 8
Agnes Ahlberg I'll try to make some time over the next week or so. But I'm not sure I know the context of generics being avoided or annoying to use as mentioned by Kiwwi#. Generics are highly powerful in decoupling from concrete implementations and heavily used in every professional C# project I've ever been involved in. Abstract classes play a much smaller role these days as we do tend to focus on composition over inheritance by way of generic bindings against interfaces. Furthermore, I'm not sure what the context of this builder class is or what it's building exactly. Is it transient or long life cycle? Is it dynamic based on conditions or consistent based on usage? I'm referring to very high level design topics that could morph into greater discussions and many paths that could be explored with different design patterns. The preferred approach these days is to delegate construction patterns to DI Containers which are implemented in the application startup code using various middleware hooks and such.
19th Sep 2021, 5:37 AM
David Carroll
David Carroll - avatar
+ 8
I would focus more on understandings SOLID Principles and how to leverage design patterns to preserve those principles. It's about buildings maintainable code that isn't brittle to evolving code iterations. Part of that involves a decent unit tests. Design patterns can be used to enforce patterns that work in this goal for managing code uodates over time. The static method used for extension of the class isn't really a method extension. Not sure if you were using that term generically or not. It appears the intent is for the static method to resolve the type to build based on a string value. That is introducing tight coupling without static type checking, which is a recipe for disaster in the future. Furthermore, the static method requires being updated when new types are added and need to be supported. This violates the Open / Close Principle, which is overlooked by this code sample. Anyway, I hope I provided some new references you can dig through in research to learn more about these concepts.
19th Sep 2021, 5:52 AM
David Carroll
David Carroll - avatar
+ 4
Classes can be a good way to organize code that can be enhanced, extended later more easily. In a real project, unlike SoloLearn, we would keep each class in a separate file. So adding a new strategy can be done easily by adding a new file without changing existing code. But the same argument can be true for functions also, adding a new one in an existing file is not a big deal. In the meantime I did some experiment with the delegate too! https://code.sololearn.com/cLqj0Rcgqd4w/?ref=app
15th Sep 2021, 7:45 PM
Tibor Santa
Tibor Santa - avatar
+ 4
I feel like Agnes Ahlberg; there's so much to learn. C# encourages Composition over Inheritance. Don't know if it goes with this case, but in general better use Composition if can. Heard that many avoid use generics as much as possible; those are annoying to use. Tibor Santa the Clojure link you shared looks good. idk Clojure but seems to be similar to C#/Java. The basic notion I get from it is that the most of the stuff logic regarding patterns can be emulated/wrapped by a single function and then use it in some ways (delegates, etc)
15th Sep 2021, 10:30 PM
Kiwwi#
Kiwwi# - avatar
+ 3
In my opinion, design patterns are overrated.. And often misused, introducing unnecessary complexity. Yes, they were invented by really smart people, to solve real problems, related to code maintenance and reusability. But at that time, OOP was still in its infancy, and people tried to solve every problem with inheritance. Since then a lot has happened, and most languages including C# have access to functional tools, which enable us to think about the same problems in different ways. To me, this piece was a real eye-opener... http://mishadoff.com/blog/clojure-design-patterns/ Well, it is comparing Java with Clojure, but the essence is that most known design patterns can be implemented with functions as well. As to C# I am really not an expert. But let's see. The strategy pattern means that we want to pass a different *behavior* to a method, based on some condition. A behavior is best expressed as a function. C# has first-class Func<> and Action<> generic constructs that can do this, and also has delegates.
15th Sep 2021, 6:35 PM
Tibor Santa
Tibor Santa - avatar
+ 3
(part 2) A stackoverflow post about passing functions as argument : https://stackoverflow.com/questions/3622160/c-sharp-passing-function-as-argument So I think, rather than doing the inheritance business with or without generics, as you proposed, you could simply pass a function (=behavior) to your string processing program, and this would satisfy the Strategy Pattern. As to your actual question, whether abstract class or generic solution is better, I would leave the argument to someone more experienced in C# than myself. Maybe David Carroll or rudolph flash would be intrigued by this post. I certainly found it very interesting. My older attempt at strategy pattern in Java, just as reference: https://code.sololearn.com/cs5Ex69y2err/?ref=app
15th Sep 2021, 6:42 PM
Tibor Santa
Tibor Santa - avatar
+ 3
Kiwwi# "Composition over Inheritance" is more of an OOP concept, the principle is to build up separate functionality as different interfaces (or abstract class) , and combine them to the final usable classes.. Rather than creating a deep hierarchy of subclasses with each adding just a little change... Because that would result in very fragile design. I think the delegate is a new paradigm over this, and is closer to "function composition". In my example I did not define any classes or interfaces :) Clojure language is totally different from Java or C#, in fact it is the complete opposite. It is a LISP dialect, it has dynamic typing, and is a functional language (not OOP). But it runs in the JVM and can interoperate with Java code. Not mainstream but it is my secret favorite. I also made some tutorials about it. (sorry if this was slightly offtopic) https://code.sololearn.com/WOeAGd3KX3MR/?ref=app
16th Sep 2021, 4:46 AM
Tibor Santa
Tibor Santa - avatar
+ 3
Tibor Santa good to share info. dynamic typing is a new concept to me.
16th Sep 2021, 5:14 AM
Kiwwi#
Kiwwi# - avatar
+ 3
Thank you both ๐Ÿค—๐Ÿ’• I have found that generics do not work well with the builder pattern. The builder pattern is meant to abstract away from the actual classes, but generics want a concrete type ๐Ÿค”๐Ÿค“ Since my cypher classes work differently, the do not work well with the builder pattern (which I first tried ๐Ÿ˜ฐ). The user needs to specify exactly which cypher method they want to use. Therefore, I chose generics for the context ๐Ÿค“ Here is the code: https://code.sololearn.com/cKkcKA42RjZb Sorry, it's a bit long ๐Ÿ™‚
17th Sep 2021, 6:05 PM
Agnes Ahlberg
Agnes Ahlberg - avatar
+ 3
The conclusion is that to obtain results isn't necessary fit completely the standards of a pattern, but use something that works well and is simple. Otherwise it can easily become a limitation to feel enforced to satisfy "the tyranny" of the design patterns. Most of the basic features of both, the language being used and the agnostic stuff works well the most of the time. Something similar happens with design principles.
18th Sep 2021, 2:03 AM
Kiwwi#
Kiwwi# - avatar
+ 3
Thank you ๐Ÿค—๐Ÿ’• Yes, I did realise that the builder method would require updaing. I wasn't all too happy with that ๐Ÿค” But I don't know any other way to add something that is not yet there. Perhaps "extension" is reserved word. I meant to express that the added type provides abilities that the generic class does not have or know how to do (encrypting/decrypting). That way I wanted to write a class that can take and modify plain text - and how to encrypt it is like a module that is attached to it via the generic type ๐Ÿ™‚ That worked ... sort of ๐Ÿ˜… I'm not too happy with my solution, that is why I asked ๐Ÿ˜‡ I have to read up on transient, long-term, SOLID, DI containers, and all the other technical expressions first. But thank you for now. This discussion certainly paid off and is pointing me to new concepts to study so that I get a better picture ๐Ÿค—๐Ÿ’•
19th Sep 2021, 6:22 AM
Agnes Ahlberg
Agnes Ahlberg - avatar
+ 3
Just one question: is a tight coupling between a class that builds and the object being built not necessary? ๐Ÿค” It seems to me only natural since the builder needs to know the things it is supposed to build ๐Ÿค” Edit: Having just read a bit about DI Containers, I think I can answer this question myself now ๐Ÿ˜ƒ The idea is to tell the builder how to build. That way, the builder does not depent directly on the objects it is supposed to build. Actually, it can build anything ๐Ÿ˜ƒ That's clever ๐Ÿค“ And gives me a whole new perspective of my project ๐Ÿ˜ƒ
19th Sep 2021, 6:27 AM
Agnes Ahlberg
Agnes Ahlberg - avatar
+ 2
Thank you ๐Ÿค—๐Ÿ’• Yes, I have read about delegates ๐Ÿ™‚ But there are so many concepts to learn, it is really overwhelming ๐Ÿ˜ฐ. But I will look into it. Certainly, methods could be used to pass behaviour. But it seems to me that classes are better suited to store behaviour, especially if it is rather complex behaviour ๐Ÿค” What do you think? ๐Ÿ™‚
15th Sep 2021, 7:39 PM
Agnes Ahlberg
Agnes Ahlberg - avatar
+ 2
David Carroll by all means, take your time. A late response is better still than none ๐Ÿ˜‡ And a comment on the issues as well as the correct use of generics and their (dis-)advantage over abstract classes or interfaces would be much appreciated ๐Ÿค“
19th Sep 2021, 2:55 AM
Agnes Ahlberg
Agnes Ahlberg - avatar
+ 2
David Carroll how generics help to decouple? (think my thoughts on generics are based on my origins /w C++ templates, for me generics can turn verbose and add an extra abstraction layer). Anyways if it results that are better to use than first glance, can change my opinion though. You mean that generics are being used instead of interfaces? notable concepts: * DI containers * transient - long life-cycle * dynamic conditional - consistent on usage
19th Sep 2021, 5:51 AM
Kiwwi#
Kiwwi# - avatar
+ 2
Thank you, I will ๐Ÿ™‚
19th Sep 2021, 7:23 AM
Agnes Ahlberg
Agnes Ahlberg - avatar
+ 2
I am prepared now ๐Ÿ™‚ I read about SOLID and DI Containers, with lots of examples ... Every example of a DI container explicitly mentioned that one would not implement them that way, but I think I got the idea ๐Ÿ™‚ I suppose there are commercial or open-source DI containers that would be used ๐Ÿค”
21st Sep 2021, 6:28 PM
Agnes Ahlberg
Agnes Ahlberg - avatar
+ 2
In what context? ๐Ÿค” In the SOLID context, or my project? For the first, it would seem DI is the D part of SOLID, for my project, I hope to find out ๐Ÿ™‚
22nd Sep 2021, 3:32 AM
Agnes Ahlberg
Agnes Ahlberg - avatar