2

I think I kind of reinvent caching in Java but have a point I don't get further. In case the answer is anywhere on Stackoverflow for this issue I might had not understood it when searching or didn't understand the required complexity and searched for a more easy way.

Short what I want to do: call a method on an Object. The object should load a picture and store it as Image. Then it should decorate itself with an Decorator so that called method will next time only return the image with no more IO operations.

My Interace Picture Interafce is simple like this:

import java.awt.*;

public interface PictureInterface {

    public Image getImage();

}

My Decorator looks like this:

import java.awt.*;

public class PictureDecorator implements PictureInterface {

    private final Picture p;

    public PictureDecorator(Picture p){
        this.p = p;
    }

    public Image getImage(){
        return this.p.pipeImage();
    }

}

It saves a Picture and on getImage() calls pictures pipeImage - the picture "real" getImage().

And last but not least the Picture Class:

import java.awt.Image;

public class Picture implements PictureInterface{

    private final String path;
    private final Image image;

    public Picture(String path){
        this.path = path;

    }

    private void loadImage(){
        this.image = /*IO Magic Loading the Image from path*/
    }

    public Image getImage() {
        loadImage();
        /*Decorate Yourself with Picture Decorator*/
        return /*Decorator.getImage*/;
    }

    Image pipeImage(){
        return this.image;
    }
}

If getImage is called I want Picture to Decorate itself and call the Decorators getImage and most importent overwrite its old refference (Java is call by value, this is where i'm stuck atm) so on further getImage Calls the Decorators getImage Method is called.

As a little extra-question I think my access to the mage from Decorator is not best practice, hints welcome ^^

EDIT:

To add a thing: I allready thought if this it not possible: what would be "smarter": go for if(image==NUll) or make a decorateYourself() function where image is loaded and decorator returned in Picture and in Decorator it only returns itself, apply this to the Image var and then call getImage, like:

ImageInterface x = new Image("path);

x = x.decorateYourself()
Image i = x.getImage()

this ways i would only do a method-call to return the decorator itself, but i have to call both methods ...

SchreiberLex
  • 482
  • 1
  • 4
  • 25
  • Why not simply `if( image == null ) loadimage(); return image;` ? If needed add some threadsafety ... – Fildor Jan 17 '17 at 11:32
  • 1
    take a look into http://stackoverflow.com/questions/4886485/in-java-concurrency-in-practice-by-brian-goetz . – Vlad Bochenin Jan 17 '17 at 11:39
  • You should call `loadImage()` after setting path in the Picture constructor. – TiyebM Jan 17 '17 at 11:43
  • 1
    @TiMr Why that? What if he never needs the actual image but only the path? Spoiled memory ... – Fildor Jan 17 '17 at 11:44
  • @Fildor the problem is that he never called `this.p.getImage()` but instead `this.p.pipeImage();` – TiyebM Jan 17 '17 at 11:49
  • 1
    @TiMr There is no `this.p.getImage()`. That's the point. OP wants to lazy load and then use that result in each subsequent call to `getImage()`. – Fildor Jan 17 '17 at 11:52

1 Answers1

2

If getImage is called i want Picture to Decorate itself and call the Decorators getImage and most importent overwrite its old refference (Java is call by value, this is where i'm stuck atm) so on further getImage Calls the Decorators getImage Method is called.

A decorator doesn't work in this way.
With decorator you want to augment or diminish a behavior of an existing class without being invasive for this class : no needed modification.
So the decorator instance decorates an object that has to share with the decorator class a common type and a common method.

Besides I don't think that you need to use a decorator. Here you don't decorate a picture but you bypass its loading if it was already previously performed.

I think that it would be more suitable to use a proxy that decides whether it must load the resources of get it from the cache.
Don't worry, it doesn't change many things in the classes you have introduced: interface, common method and object wrapping are still required.

In your case PictureInterface is the common type between the proxy class and the proxy subjects classes that provides the common method : getImage().

import java.awt.*;

   public interface PictureInterface {        
        public Image getImage();        
    }

PictureProxy, a proxy class could implement PictureInterface to act as any PictureInterface instances.

PictureProxy should be responsible to check if it has cached the result of a previous loading of the image. It is the case it returns it. Otherwise it calls getImage() on the Picture instance that holds and it caches the result.

import java.awt.*;

public class PictureProxy implements PictureInterface {

    private final Picture p;
    private final Image image;

    public PictureProxy(Picture p){
        this.p = p;
    }

    public Image getImage(){
        if (image != null){
           return image;
        }
        image = p.getImage();
        return image;
    }
}

And Picture class should not be aware of the proxy when it performs getImage(). It is the proxy class that handles the state of the cache.

import java.awt.Image;

public class Picture implements PictureInterface{

    private final String path;
    private final Image image;

    public Picture(String path){
        this.path = path;   
    }

    private void loadImage(){
        this.image = /*IO Magic Loading the Image from path*/
    }

    public Image getImage() {
        loadImage();
        return image;
    }           
}

From the client of the classes you could do something like that :

Picture picture = new PictureProxy(new Picture("picturePath"));
Image img = picture.getImage(); // load the image from Picture the first time and get it
Image img = picture.getImage(); // get it from the PictureProxy cache
davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • This is kind of what Fildor wrote in his comment and i don't know how this would be better than checking for cahched value inside Picture itself then. Anyways thx for your work on this answer, not what i look for, but teached me something about proxys :) – SchreiberLex Jan 17 '17 at 12:08
  • You are welcome :) If you use a single class (`Picture`) and you cache the image value inside this class, you mix caching and basic features of the picture concept in the `Picture class`. It may be desirable as it may not be. If you think than all Pictures should have the caching mechanism, you could do it. Otherwise if it is not the case or you need other methods in Picture (as clean the cache for example or giving some parameter to the cache behavior) that have side effect on the cached image you should use a separate class. – davidxxx Jan 17 '17 at 12:25
  • That Comment wraps up everything further i need to know. Guess i have to bury my idea then. – SchreiberLex Jan 17 '17 at 12:29