CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 3 of 3
  1. #1
    Join Date
    Mar 2012

    Design id to store vectors for CAD program


    I am poking my head on a new design for LibreCAD (http://librecad.org) and looking for some opinions.

    Let's say we have entities like lines and circles. And each entity can have a pen attached. And a pen is a color and line width. All entities needs to be manipulated through a operations interface.
    All entities added to the program needs to be added through using a factory pattern.

    So we end up something like (pseudo code)

    class Line // for immutable objects

    class MutableLine extends Line //for mutable lines

    MutableLine line=factory->newLine(20,20,50,50); // Create a new line entity
    line->setPen(Pen(Color("red"), 2)); // red pen, 2mm
    MutableCircle circle=factory->newCircle(20,20,30); // Create a new line entity, default pen
    line->setPen(Pen("ByLayer")); // pen set by layer

    // Select all entities in this box
    document -> selectEntities(0,0,100,100);

    // Rotate

    // set Color

    // get entities (for export/saving)
    List myItems=document->selectedEntities();

    So, essentially I want no code to be able to operate directory on entities, unless during creation of the object (color, layer, line width etc...) so I am planning to create Mutable versions of all entities besides the immutable versions.

    When requested for selected entities or all entities, I am planning to return a list of immutable objects and in fact I am planning to return a new copy so it's not possible to operate on anything directly.
    The reason is that I am planning to create different storage backends swell, so I can operate on entities in a database, or shared memory... stuff like that. At least to hide the internals and provide a stable API.

    My questions are:

    1) Any thought on this like or don't like?
    2) How can I make sure that people don't do 'tricks' casts for example to a mutable version to change objects directly?
    3) Does it make sense, any place else I should look?

    Poking around a bit!


  2. #2
    Join Date
    May 2009

    Re: Design id to store vectors for CAD program

    Quote Originally Posted by rvtinec View Post
    2) How can I make sure that people don't do 'tricks' casts for example to a mutable version to change objects directly?
    Well, do you really need mutable objects? Immutability is a big design advantage so why not make both entities and pens immutable. Once created they never change. If another one is needed it's factory created anew.

    I don't think pen should be part of entity (*). Most of the time entities probably are going to be used without regard to how they end up being drawn eventually. Which pen to use is better postponed to that moment, like,

    canvas->draw(entity, pen)

    So the entity-pen association is highly temporary but of course it's possible to introduce more lasting ones like

    class VisibleEntity {
    Entity* entity();
    Pen* pen();

    The draw method could be overloaded to take one (or an array of) VisibleEntity objects. But it's really not necessary to support a VisibleEntity-style class in the library because users could easily create such associations themselves that are maybe more suitable for specific applications. Or simply use std::pair.

    Also note that to handle both primitive entities as well as compositions of entities uniformly there's a suitable design pattern called Composite.

    (*) Because it's not a true composition (has-a) relationship. An entity is not composed of a pen. It's rather a temporary aggregation relationship. A pen is used while an entity is being drawn.
    Last edited by nuzzle; March 5th, 2012 at 04:04 AM.

  3. #3
    Join Date
    Jan 2010

    Re: Design id to store vectors for CAD program

    2) How can I make sure that people don't do 'tricks' casts for example to a mutable version to change objects directly?
    Nuzzle makes some good points - treating the pen as contextual information will provide you with more flexibility. Also (and I'm not talking necessarily about the Pen here, but more hypothetically), if you maintain this kind of "temporarily related" data, as he called it, inside your entity objects, there's a good chance that you'll run into inconveniences at some point, in order to access that data from a different, but related class, for example, if there is a parallel hierarchy.

    Anyway, if you must have both mutable and immutable variants, you can wrap the mutable type by an immutable wrapper - immutable, at least, from the user's perspective (by design).
    If the user has no way of getting the internal object, than the composite is immutable as far as client code is concerned.

    I don't code much in C++, but IIRC, C++ can support this, maybe by using the friend specifier?
    In C# (and Java I think) you can specify class-level visibility, and one option is internal visibility. This access specifier can be applied to class members as well, and it basically specifies what UML calls package visibility (e.g., only visible to code within the same DLL).
    The point is: create a wide interface for your system (for internal use), and a narrow interface for the user (client code).

    I believe you could make the part of the wrapper's interface that could expose the internal object private, and make the (internal) class that sets or manipulates it a friend of the wrapper class.

    Another thing to consider: make sure there is no way for the user to have a variable pointing to the internal object; for example, if you get a pointer from the client code, make a deep copy. Otherwise, client code will be able to mutate the object.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts

Windows Mobile Development Center

Click Here to Expand Forum to Full Width

On-Demand Webinars (sponsored)

We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.