ArrayList
of 1 and save the value there. But it's not entirely flexible to always save it to a list. Perhaps I want to save it to a file instead or somewhere else etc. Having an abstraction Variable
helps to specify different locations to save the value.
@amihaiemil
When that happens, the "persecuted" one should stand up and debate. Nowadays we just have offended pussies and political correctness... same as in Yegor's article: everyone got offended and misunderstood the point. Everyone thought it was an article about women in tech, when women in tech was a mere example. r"
Did you read the quotes? they are not even from the article. They are from the comments, from yegor - him trying hard to explain himself.
He never said he would discriminate a woman. He just stated his opinion, used only the word "would"... "I would tell her not to work in tech" not "I would stop he
No, I think it's a bit worse, he's fine discriminating any person, according to his ancient style of living.
@fabriciofx Yes, this was my initial design, to have anArrayList
of 1 and save the value there. But it's not entirely flexible to always save it to a list. Perhaps I want to save it to a file instead or somewhere else etc. Having an abstractionVariable
helps to specify different locations to save the value.
ArrayList
....
@fabriciofx Well, since you put it that way, I'm starting to see nothing wrong with ArrayList
as well :D But just to reiterate what I had in mind...
There might be cases where using ArrayList
is insufficient, where, let's say, you have a lot of such cached objects and thus you're dealing with memory issues, so you decide to serialize it to a file or send it to some server, hadoop storage, whatever. You're right, this would be slow to retrieve in common scenarios, but for some values still faster (what if the value we're after requires an entire game to be played, in declarative programmer that is very possible).
There might also be other cases. Instead of using a plain ArrayList
, you would use a decorated one, where in addition to add
method it would also log the value or something... In that case, Cached
class needs to allow users to specify where to cache stuff, be it a file, a cloud, etc.
You asked for a problem description, so here it is. I would like to use Cached
in classes like these:
/** The class that computes a value. */
public final class UrlHostNameStartIndex implements HostNameStartIndex
{
private final String url;
public UrlHostNameStartIndex(String url) {
this.url = url;
}
public int toInt() {
// ...
}
}
/** a decorator that caches the computed value */
public final class CachedHostNameStartIndex implements HostNameStartIndex
{
private final Cached<Integer> index;
public CachedHostNameStartIndex(UrlHostNameStartIndex index) {
this(
new Cached<>(
new Origin<>() {
public Integer value() {
return index.toInt();
}
}
)
);
}
public CachedHostNameStartIndex(Cached<Integer> index) {
this.index = index;
}
public int toInt() {
return this.index.value();
}
}
I hope that it's easy to understand. Sure, for small objects like these two, it's enough to have an ArrayList
. I just thought it'd be cool, if Cached
allowed me to specify a different location of the value, for cases not yet discovered that may come up in the future. And that brings me back to my original question, is there a way to do that without making Cached
look like a configurable object.
new Logging(new Cached(new Abc())).value()
. Or your problem is how Cached
store the object (ArrayList
)? In this case you can create another parameter to receive which implementation use to store the object into cached.
@yegor256 @fabriciofx @ixmanuel Wouldn't a parameter make the object a "configurable object"?
Here's the Cached
class if we use a parameter:
public final class Cached<T>
{
private final Variable<T> variable;
private final Origin<T> origin;
public Cached(Variable<T> variable, Origin<T> origin) {
this.variable = variable;
this.origin = origin;
}
public T value() {
if(!this.variable.initialized()) {
this.variable.initialize(this.origin.value());
}
return this.variable.value();
}
}
It seems to me like through Variable
parameter we're injecting foreign behaviour. This class greatly depends on the implementation of this parameter and now the logic of Cached
is in the hands of an outside object.
I'm trying to understand that fine line between proper composition and configurable objects. This case seems odd to me.
public final class Cached<T>
{
private final <T> result;
public Cached(Variable<T> variable) {
this.variable = variable;
}
public T value() {
if(this.result != null) {
this.result = this.variable.value());
}
return this.result;
}
}
@mdbs99 Sure, the Variable
implementation could be using null:
public final class NullVariable<T> implements Variable<T>
{
private T var;
public boolean initialized() {
return this.var == null;
}
public void initialize(T value) {
this.var = value;
}
public T value() {
return this.value;
}
}
It could also be used with ArrayList
such as:
public final class ArrayListVariable<T> implements Variable<T>
{
private final ArrayList<T> list = new ArrayList<T>(1);
public boolean initialized() {
return !this.list.isEmpty();
}
public void initialize(T value) {
this.list.add(value);
}
public T value() {
return this.list.get(0);
}
}
which is, in my opinion, better because it avoids the usage of null.
The initialize
method in NullVariable
does what a setter does, of course, that's why I don't like it. However, in ArrayListVariable
it calls add
, so it's not really a setter anymore. Overall, i don't think you can call initialize
a setter because it may behave differently depending on the implementation.
@justasbieliauskas
...which is, in my opinion, better because it avoids the usage of null.
I agree. My example is just to show you a simpler way to do the same, without using Origin
.
Why not? I imagine a lot of duplicate code without a generic class to take care of caching.
+1
Cached
to each type
Maybe we need a specific
Cached
to each type
So you will copy the "IF" in all these classes?