I have a class as follows:
data class ProductState(
val id: Int,
val products: MutableMap<Int, MutableSet<Int>> = mutableMapOf(),
val customerTopics: Topic = Topic()
)
It is basically a data class.
Now I have a function that among other things, processes the products and customerTopics and creates some output based on the processing.
But it seems to me that it is not a good idea to have the logic in the function.
My question is:
Do we create methods inside the data class for the processing of the object'state? If so would it be some companion object? Or is there some other design pattern that deals with this better?
In kotlin you have several options:
Additional method on the data class (if it should be called in multiple other places);
Public extension method in the same file as the data class (if it should be called in multiple other places but you want to keep your data class simple and have the handling methods separated);
Private extension method in the same file as the only place where it is called (this only applies if this processing is to be called in a single place in your code);
Private method in the only place where this processing is needed.
The best place really depends on what the processing is (is it very specific to ProductState or does it need additional data? If it is very specific then it may make sense to keep it as a ProductState method or an extension function) and in how many places it will be triggered (if in a single very specific place, then maybe keeping it along-side that piece of code as a private extension function or private method might be the best option).
Related
I know what classes are about, but for better understanding I need a use case. Recently I discovered the construct of data classes. I get the idea behind normal classes, but I cannot imagine a real use case for data classes.
When should I use a data class and when I use a "normal" class? For all I know, all classes keep data.
Can you provide a good example that distinguishes data classes from non-data classes?
A data class is used to store data. It's lighter than a normal class, and can be compared to an array with key/value (dictionary, hash, etc.), but represented as an object with fixed attributes. In kotlin, according to the documentation, that adds those attributes to the class:
equals()/hashCode() pair
toString() of the form "User(name=John, age=42)"
componentN() functions corresponding to the properties in their order of declaration.
copy() function
Also it has a different behavior during class inheritence :
If there are explicit implementations of equals(), hashCode(), or toString() in the data class body or final implementations in a
superclass, then these functions are not generated, and the existing
implementations are used.
If a supertype has componentN() functions that are open and return compatible types, the corresponding functions are generated for the
data class and override those of the supertype. If the functions of
the supertype cannot be overridden due to incompatible signatures or
due to their being final, an error is reported.
Providing explicit implementations for the componentN() and copy() functions is not allowed.
So in kotlin, if you want to describe an object (a data) then you may use a dataclass, but if you're creating a complex application and your class needs to have special behavior in the constructor, with inheritence or abstraction, then you should use a normal class.
I do not know Kotlin, but in Python, a dataclass can be seen as a structured dict. When you want to use a dict to store an object which has always the same attributes, then you should not put it in a dict but use a Dataclass.
The advantage with a normal class is that you don't need to declare the __init__ method, as it is "automatic" (inherited).
Example :
This is a normal class
class Apple:
def __init__(size:int, color:str, sweet:bool=True):
self.size = size
self.color = color
self.sweet = sweet
Same class as a dataclass
from dataclasses import dataclass
#dataclass
class Apple:
size: int
color: str
sweet: bool = True
Then the advantage compared to a dict is that you are sure of what attribute it has. Also it can contains methods.
The advantage over to a normal class is that it is simpler to declare and make the code lighter. We can see that the attributes keywords (e.g size) are repeated 3 times in a normal class, but appear only once in a dataclass.
The advantage of normal class also is that you can personalize the __init__ method, (in a dataclass also, but then you lose it's main advantage I think) example:
# You need only 2 variable to initialize your class
class Apple:
def __init__(size:int, color:str):
self.size = size
self.color = color
# But you get much more info from those two.
self.sweet = True if color == 'red' else False
self.weight = self.__compute_weight()
self.price = self.weight * PRICE_PER_GRAM
def __compute_weight(self):
# ...
return (self.size**2)*10 # That's a random example
Abstractly, a data class is a pure, inert information record that doesn’t require any special handling when copied or passed around, and it represents nothing more than what is contained in its fields; it has no identity of its own. A typical example is a point in 3D space:
data class Point3D(
val x: Double,
val y: Double,
val z: Double
)
As long as the values are valid, an instance of a data class is entirely interchangeable with its fields, and it can be put apart or rematerialized at will. Often there is even little use for encapsulation: users of the data class can just access the instance’s fields directly. The Kotlin language provides a number of convenience features when data classes are declared as such in your code, which are described in the documentation. Those are useful when for example building more complex data structures employing data classes: you can for example have a hashmap assign values to particular points in space, and then be able to look up the value using a newly-constructed Point3D.
val map = HashMap<Point3D, String>()
map.set(Point3D(3, 4, 5), "point of interest")
println(map.get(Point3D(3, 4, 5))) // prints "point of interest"
For an example of a class that is not a data class, take FileReader. Underneath, this class probably keeps some kind of file handle in a private field, which you can assume to be an integer (as it actually is on at least some platforms). But you cannot expect to store this integer in a database, have another process read that same integer from the database, reconstruct a FileReader from it and expect it to work. Passing file handles between processes requires more ceremony than that, if it is even possible on a given platform. That property makes FileReader not a data class. Many examples of non-data classes will be of this kind: any class whose instances represent transient, local resources like a network connection, a position within a file or a running process, cannot be a data class. Likewise, any class where different instances should not be considered equal even if they contain the same information is not a data class either.
From the comments, it sounds like your question is really about why non-data classes exist in Kotlin and why you would ever choose not to make a data class. Here are some reasons.
Data classes are a lot more restrictive than a regular class:
They have to have a primary constructor, and every parameter of the primary constructor has to be a property.
They cannot have an empty primary constructor.
They cannot be open so they cannot be subclassed.
Here are other reasons:
Sometimes you don't want a class to have a copy function. If a class holds onto some heavy state that is expensive to copy, maybe it shouldn't advertise that it should be copied by presenting a copy function.
Sometimes you want to use an instance of a class in a Set or as Map keys without two different instances being considered as equivalent just because their properties have the same values.
The features of data classes are useful specifically for simple data holders, so the drawbacks are often something you want to avoid.
I have am trying to create a recursive data class like so:
data class AttributeId (
val name: String,
val id: Int,
val children: List<AttributeId>?
)
The thing I'm struggling with now is building the data class by iterating over a source object.
How do I recursively build this object?? Is a data class the wrong solution here?
EDIT: Some more information about the Source object from which I want to construct my data class instance
The source object is a Java Stream that essentially* has the following shape:
public Category(final String value,
final Integer id,
final List<Category> children) {
this.value = value;
this.id = id;
this.children = children;
}
(For brevity the fields I don't care about have been removed from example)
I think I need to map over this stream and call a recursive function in order to construct the AttributeId data class, but my attempts seem to end in a stack overflow and a lot of confusion!
I don't think there's anything necessarily wrong with a data class that contains references to others.
There are certainly some gotchas. For example:
If the list were mutable, or if its field was mutable (i.e. var rather than val), then you'd have to take care because its hashcode &c could change.
And if the chain of links could form a loop (i.e. you could follow the links and end up back at the original class), that could be very dangerous. (E.g. calling a method such as toString() or hashCode() might either get stuck in an endless loop or crash the thread with a StackOverflowError. You'd have to prevent that by overriding those methods to prevent them recursing.) But that couldn't happen if the list and field were both immutable.
None of these issues are specific to data classes, though; a normal class could suffer the same issues (especially if you overrode methods like toString() or hashCode() without taking care). So whether you make this a data class comes down to whether it feels like one: whether its primary purpose is to hold data, and/or whether the automatically-generated methods match how you want it to behave.
As Tenfour04 says, it depends what you're constructing these from. If it naturally forms a tree structure, then this could be a good representation for it.
Obviously, you wouldn't be able to construct a parent before any of its children. (In particular, the first instance you create would have to have either null or an empty list for its children.) This would probably mean traversing the source in post-order. The rest should fall out naturally from that.
We are currently switching our project to Kotlin, and ran across following question:
We need a certain extension function only inside a given class. Thus, we have two possibilities: (1) Declaring the extension function private on the file top-level or (2) declaring the extension function private inside the class.
Following a MCVE:
Top-level example (file C1.kt):
private fun String.double() = this.repeat(2)
class C1 {
init {
println("init".double())
}
}
Inside class example (file C2.kt):
class C2 {
private fun String.double() = this.repeat(2)
init {
println("init".double())
}
}
Questions:
Is there any difference to those two approaches, except that in C1.kt the extension function String.double() would also be visible to other possible file members (such as further classes in the same file)?
Since we want to achieve code "as kotlinic as possible", we would like to know which of the two approaches is the suggested one. Is there an official suggestion / style guide on the example above? I think it is considered good practice to declare extension functions as close as possible to its intended use, thus in the above example the structure of C2 would be suggested?
Is there any difference to those two approaches, except that in C1.kt the extension function String.double() would also be visible to other possible file members (such as further classes in the same file)?
There is one difference: When specifying an extension function inside the class (in your example C2), then you additionally have access to the instance of this class with the qualified this syntax (in your example this#C2).
Since we want to achieve code "as kotlinic as possible", we would like to know which of the two approaches is the suggested one. Is there an official suggestion / style guide on the example above? I think it is considered good practice to declare extension functions as close as possible to its intended use, thus in the above example the structure of C2 would be suggested?
That's a good question. Personally, I would put the extension functions outside the class, since they (normally) specify behavior that is related to the extended type and not to the type of the class where they are used. However, if you do need class-related information within the extension function, I would then specify them inside the class.
I learned from one example, so I am not sure if this is the optimal way or not, but anyways, I use the following code. I create one Retrofit instance and use it for all requests.
Since there are many methods, there are many types of data. It seems that I can create adapters (json -> my data class) automatically simply by adding annotations. But I needed more control (inheritance: the data classes have shared fields, dependency: some fields may not exist depending on other field's values), so I created a custom adaptor for each of the classes. So, currently my code is like this:
if (instance == null)
{
val gson = GsonBuilder()
.registerTypeAdapter(myClass1::class.java, myClassDeserialiser1())
.... (tens of this) ....
.registerTypeAdapter(myClass30::class.java, myClassDeserialiser30())
.create()
instance = Retrofit.Builder().
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(MyAPIs::class.java);
}
return instance
The problem above is that I am creating instances of all parsers at the same time in advance. This may be inefficient. I wish I could create them when they are first needed. Is that possible?
You can add a #JsonAdapter annotation to your class definition in lieu of calling registerTypeAdapter. I can't comment on its efficiency, but it keeps the adapter info tied to the object instead of the creation of your Gson object, which sounds like what you want.
I have an object called Parameters that gets tossed from method to method down and up the call tree, across package boundaries. It has about fifty state variables. Each method might use one or two variables to control its output.
I think this is a bad idea, beacuse I can't easily see what a method needs to function, or even what might happen if with a certain combination of parameters for module Y which is totally unrelated to my current module.
What are some good techniques for decreasing coupling to this god object, or ideally eliminating it ?
public void ExporterExcelParFonds(ParametresExecution parametres)
{
ApplicationExcel appExcel = null;
LogTool.Instance.ExceptionSoulevee = false;
bool inclureReferences = parametres.inclureReferences;
bool inclureBornes = parametres.inclureBornes;
DateTime dateDebut = parametres.date;
DateTime dateFin = parametres.dateFin;
try
{
LogTool.Instance.AfficherMessage(Variables.msg_GenerationRapportPortefeuilleReference);
bool fichiersPreparesAvecSucces = PreparerFichiers(parametres, Sections.exportExcelParFonds);
if (!fichiersPreparesAvecSucces)
{
parametres.afficherRapportApresGeneration = false;
LogTool.Instance.ExceptionSoulevee = true;
}
else
{
The caller would do :
PortefeuillesReference pr = new PortefeuillesReference();
pr.ExporterExcelParFonds(parametres);
First, at the risk of stating the obvious: pass the parameters which are used by the methods, rather than the god object.
This, however, might lead to some methods needing huge amounts of parameters because they call other methods, which call other methods in turn, etcetera. That was probably the inspiration for putting everything in a god object. I'll give a simplified example of such a method with too many parameters; you'll have to imagine that "too many" == 3 here :-)
public void PrintFilteredReport(
Data data, FilterCriteria criteria, ReportFormat format)
{
var filteredData = Filter(data, criteria);
PrintReport(filteredData, format);
}
So the question is, how can we reduce the amount of parameters without resorting to a god object? The answer is to get rid of procedural programming and make good use of object oriented design. Objects can use each other without needing to know the parameters that were used to initialize their collaborators:
// dataFilter service object only needs to know the criteria
var dataFilter = new DataFilter(criteria);
// report printer service object only needs to know the format
var reportPrinter = new ReportPrinter(format);
// filteredReportPrinter service object is initialized with a
// dataFilter and a reportPrinter service, but it doesn't need
// to know which parameters those are using to do their job
var filteredReportPrinter = new FilteredReportPrinter(dataFilter, reportPrinter);
Now the FilteredReportPrinter.Print method can be implemented with only one parameter:
public void Print(data)
{
var filteredData = this.dataFilter.Filter(data);
this.reportPrinter.Print(filteredData);
}
Incidentally, this sort of separation of concerns and dependency injection is good for more than just eliminating parameters. If you access collaborator objects through interfaces, then that makes your class
very flexible: you can set up FilteredReportPrinter with any filter/printer implementation you can imagine
very testable: you can pass in mock collaborators with canned responses and verify that they were used correctly in a unit test
If all your methods are using the same Parameters class then maybe it should be a member variable of a class with the relevant methods in it, then you can pass Parameters into the constructor of this class, assign it to a member variable and all your methods can use it with having to pass it as a parameter.
A good way to start refactoring this god class is by splitting it up into smaller pieces. Find groups of properties that are related and break them out into their own class.
You can then revisit the methods that depend on Parameters and see if you can replace it with one of the smaller classes you created.
Hard to give a good solution without some code samples and real world situations.
It sounds like you are not applying object-oriented (OO) principles in your design. Since you mention the word "object" I presume you are working within some sort of OO paradigm. I recommend you convert your "call tree" into objects that model the problem you are solving. A "god object" is definitely something to avoid. I think you may be missing something fundamental... If you post some code examples I may be able to answer in more detail.
Query each client for their required parameters and inject them?
Example: each "object" that requires "parameters" is a "Client". Each "Client" exposes an interface through which a "Configuration Agent" queries the Client for its required parameters. The Configuration Agent then "injects" the parameters (and only those required by a Client).
For the parameters that dictate behavior, one can instantiate an object that exhibits the configured behavior. Then client classes simply use the instantiated object - neither the client nor the service have to know what the value of the parameter is. For instance for a parameter that tells where to read data from, have the FlatFileReader, XMLFileReader and DatabaseReader all inherit the same base class (or implement the same interface). Instantiate one of them base on the value of the parameter, then clients of the reader class just ask for data to the instantiated reader object without knowing if the data come from a file or from the DB.
To start you can break your big ParametresExecution class into several classes, one per package, which only hold the parameters for the package.
Another direction could be to pass the ParametresExecution object at construction time. You won't have to pass it around at every function call.
(I am assuming this is within a Java or .NET environment) Convert the class into a singleton. Add a static method called "getInstance()" or something similar to call to get the name-value bundle (and stop "tramping" it around -- see Ch. 10 of "Code Complete" book).
Now the hard part. Presumably, this is within a web app or some other non batch/single-thread environment. So, to get access to the right instance when the object is not really a true singleton, you have to hide selection logic inside of the static accessor.
In java, you can set up a "thread local" reference, and initialize it when each request or sub-task starts. Then, code the accessor in terms of that thread-local. I don't know if something analogous exists in .NET, but you can always fake it with a Dictionary (Hash, Map) which uses the current thread instance as the key.
It's a start... (there's always decomposition of the blob itself, but I built a framework that has a very similar semi-global value-store within it)