I am writing a server-client program with the following idea (analogy for my real program). There are many types of shapes. The client represents the shapes to the user which can queue operations (like translation, rotation...) on them. The client sends the server the id and operation type. The server performs the operation and sends the new shape data back to the client.

In my current design I have the classes I detail below.

The Shape class sits only on the server, its subclasses contain algorithms for performing the operations for each shape (pretend that rotating a triangle and a square is very different). I do not want nor need that they be accessible to the client.

abstract class Shape {

    ShapeData data; // see below
    int[] plane; // some non-static parameter used by the server

    abstract void rotate();
    abstract void translate();
    abstract void rescale();
    // ... 10 more

The subclasses also sit only on the server

class Square extends Shape {

    void rotate()    { /* using ShapeData data and int[] plane ...*/ }
    void translate() { /*    "   */ };
    void rescale()   { /*    "   */ };

class Circle extends Shape {

    // same structure as square

// many more shapes

ShapeData is a class which holds the data of a shape (same data structure for all shapes). It is the class that is transfered from the server to the client from which the client can, for example, draw the shape. The class is also used by the server to perform the computations as seen above.

abstract class ShapeData implements Serializeable {

    int id; // after manipulating the shape represented by this class, the
            // client send this id back to the server

    int edgesNum;
    int width;
    int height;
    // ...

    // setters and getters

I understand that separating data and behavior is not an OO approach, but I treat this class as a DTO (reference).

Getting the shape data from the shape is simple as it is "composed" into it, the problem is the other way around. The server keeps a List<ShapeData> which I retrieve from by id, but there is no obvious way to get the Shape on which to apply the transformation. This lead me to think that the design is bad.

Right now I keep a Map<ShapeData, Shape> to retrieve Shape. Another way is to add an id field to Shape with the same value as in its ShapeData and keep a List<Shape> from which I retrieve by id too.

Is the design bad or is there just some modification I can do to make it work "properly"?

  • 1
    Whoever downvoted my first question on this site might want to explain why instead of expecting users to mind-read what's wrong with it. – user1803551 Dec 15 '15 at 20:38
  • Why don't you want your clients to access the server-side class? – michaelsnowden Dec 15 '15 at 21:26
  • Why Map<ShapeData, Shape> instead of Map<Integer, Shape> so that you just need the id of the shape? Also, are your shapes persistent (i.e. stored in a database)? – michaelsnowden Dec 15 '15 at 21:29
  • @michaelsnowden "Why don't you want your clients to access the server-side class?" Because they don't need it. They can't do the transformations by themselves. "Why Map<ShapeData, Shape> instead of Map<Integer, Shape>?" So I can get(data) instead of get(data.getID()), I don't see any advantage for Integer. "are your shapes persistent?" Shape objects have to be stored (in memory in this case) in order to be retrieved, which is what the question is about. – user1803551 Dec 15 '15 at 21:36
  • So your clients have some way of rotating shapes other than using the Shape class? – michaelsnowden Dec 15 '15 at 21:38

The design is not inherently bad. Let's asume the transformations to be performed on the shapes are resource consuming and that is reason enough to have the behavior un the server.

In MHO the matching id is the way to go. You then pass a List<ShapeData> object back and forth. The client receives such a list and renders the graphics. The server receives such a list and matches every ShapeData with its corresponding Shape to make transformations.


(1) Why do you prefer this approach?

To me every different type of Shape is a flyweight object, data is injected everytime a transformation is needed.

The id would help implement Chain-of_responsability pattern in which every processor object see whether the data is for them to work on they must pass it on to the next processor.

(2) The client send only the id and transformation request (not included in my classes above), I don't see why it should pass the whole unchanged data class.

So the servers doesn't have to have a permanent copy of every user's object. Objects live in the client, they are send to the server and the server sends them back transformed, servder doesn't need to have a synchronized copy of them. IMHO.

(3) So you suggest that I go with keeping a List<Shape> and search it by id

That way you could implement chain-of_responsability and flyweight patterns.

  • Thanks for the reply. Questions: (1) Why do you prefer this approach? For me, it seemed odd that an object (Shape) will contain the same field (id) that is already contained in an object (ShapeData) it itself contains. (2) The client send only the id and transformation request (not included in my classes above), I don't see why it should pass the whole unchanged data class. (3) So you suggest that I go with keeping a List<Shape> and search it by id? – user1803551 Dec 15 '15 at 20:31
  • @user1803551 So the client doesn't render the graphics? If the client renders the graphics then it should have access to ShapeData objects, shouldn't it? – Tulains Córdova Dec 15 '15 at 20:43
  • It does render them and does have access to them. I was referring to "The server receives such a list" - the server doesn't receive ShapeData, just the id from it so it would know which one to retrieve from the List<ShapeData> is keeps, and an instruction for transformations. – user1803551 Dec 15 '15 at 20:47
  • @user1803551 I elaborated. – Tulains Córdova Dec 16 '15 at 11:38
  • Thanks, I read more into the patterns. In the link is is said that ShapeData would have to be made immutable, is this even though they have a unique id? – user1803551 Dec 17 '15 at 8:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.