Design pattern question

Discussion in 'C++' started by Chris F Clark, Nov 1, 2004.

  1. 1) I would really like to ask this on comp.lang.c#, but no such group
    exists. However, perhaps someone in one of the above two groups
    will know the answer and help me out.

    In my product, I use a variation of a design pattern called
    "generation gap". In particular, there is library code that knows
    about certain classes that are user customized and generated with
    those customizations on behalf of the user. This is done via "opaque"
    types. I'll show a C++ implementation w/o namespaces in a sec.
    However, I want to do a similar idea in C# (and in Java). The problem
    is that I can't figure out how to do this pattern in a namespace
    compatible way.

    Library Code:

    typedef class UserClass *UserClassPtr;

    class SomeLibraryClass {
    UserClassPtr someMemberFunction(); // UserClass is "opaque" here
    }

    ////////////////////////////////////////////////////////////////////
    Generated Code:

    typedef class UserClass *UserClassPtr;

    class UserClass {
    int userSpecificMemeber; // User customizations
    }

    class GeneratedClass : public SomeLibraryClass {
    UserClassPtr someMemberFunction()
    {
    return new UserClass(); // UserClass is NOT "opaque" here
    }
    }


    ////////////////////////////////////////////////////////////////////

    The above scheme works relatively well in C++.

    I can put the implementation details in the library code and compile
    it once. The library can also give the abstract interface that users
    can know about the generated classes. This allows users to write
    programs to that abstract interface without knowing the details of the
    actual generated classes. The UserClass which they can customize
    however, is an important part of that. If the system were a
    event-driven GUI, this data might be thought of as the "call back"
    data. In old C language programs, this would be a "void *" that the
    user would cast to find the right data. However, it is better that we
    make it a real type and get some level of type safety.

    That type safety is limited though, because imagine that we generate
    two or more "families" of generated classes. The library uses only
    pointers to the types, so it is relatively immune to the types.
    However, the generated code has access to the "real" UserClass type
    and it can access the members of that type. Code which is "client" to
    the library, is safe if it only uses pointers, or if it has the
    appropriate generated code family visible to it, so that it sees one
    customized version. However, if the client code sees both families,
    then ther are two definitions of the client class, and it is not safe
    for the client code to access the members.

    This brings us to the namespace issue. One solution to two classes of
    the same name is to have them in separate namespaces. However, how
    does one in the library refer something so that each generated
    namespace gets its own copy. The following doesn't work:

    namespace Library
    {

    typedef class UserClass *UserClassPtr;

    class SomeLibraryClass {
    UserClassPtr someMemberFunction(); // UserClass is "opaque" here
    }

    // Error no UserClass in Library namespace
    }

    namespace GeneratedCode
    {
    using Library;

    typedef class UserClass *UserClassPtr;

    class UserClass { // Not in Library namespace
    int userSpecificMemeber; // User customizations
    }

    class GeneratedClass : public SomeLibraryClass {
    UserClassPtr someMemberFunction()
    {
    return new UserClass(); // UserClass is NOT "opaque" here
    }
    }

    }


    The problem is particularly noticable in languages like C# where there
    are no explicit "pointer" types. I don't know how to say this is a
    "type to be defined later" (and I don't want to just say "object"
    because in real life the client software and the generated software
    are related and it is much more convenient if the type can just "pass
    thru" the system, so that the client software can easily access the
    data created for it by the (user customized version of the) generated
    code).


    Suggestions?
    -Chris
    Chris F Clark, Nov 1, 2004
    #1
    1. Advertising

  2. Chris F Clark wrote:
    > 1) I would really like to ask this on comp.lang.c#, but no such group
    > exists. However, perhaps someone in one of the above two groups
    > will know the answer and help me out.


    There is microsoft.public.dotnet.languages.csharp...

    > [...]
    > Suggestions?


    "Pointer to implementation" (pimpl) idiom
    "Handle" idiom (used a lot in MS Windows API)

    I think essentially you're looking for a base class/interface and its
    implementation. Instead of wrapping your classes from your different
    "families" in namespaces, wrap them in classes.

    Perhaps I didn't understand the problem, though.

    V
    Victor Bazarov, Nov 1, 2004
    #2
    1. Advertising

  3. Thanks for the microsoft... pointer, I'll look into it.

    > I think essentially you're looking for a base class/interface and its
    > implementation. Instead of wrapping your classes from your different
    > "families" in namespaces, wrap them in classes.


    I think you do understand the problem. The prototype was done that
    way, with an explicit "interface" class that replaced the "pointer" type.

    In the library:

    interface class UserClassPtr;

    In the generated code:

    class UserClass implements UserClassPtr
    { // customizations
    };

    However, the user community didn't like having to "cast" from the
    interface back to their concrete class to access their customizations.
    The problem being that there are quite a few library functions that
    are used in the generated code that return these objects. So, the
    user writing the customizations find themselves writing these casts
    all-the-time (perhaps several per line for perhaps a few hundred
    lines). Example:

    //Target and Source are library functions that return UserClassPtr

    UserClass(Target()).userField =
    UserClass(Source(1)).userField + UserClass(Source(2)).userField;

    compared to:

    //Target and Source are library functions that return UserClass

    Target().userField = Source(1).userField + Source(2).userField;

    -Chris
    Chris F Clark, Nov 1, 2004
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. sunny
    Replies:
    1
    Views:
    451
    Salt_Peter
    Dec 7, 2006
  2. Bartholomew Simpson

    class design/ design pattern question

    Bartholomew Simpson, Jun 12, 2007, in forum: C++
    Replies:
    2
    Views:
    443
    Daniel T.
    Jun 12, 2007
  3. Pallav singh
    Replies:
    0
    Views:
    343
    Pallav singh
    Jan 22, 2012
  4. Pallav singh
    Replies:
    0
    Views:
    389
    Pallav singh
    Jan 22, 2012
  5. Pallav singh
    Replies:
    1
    Views:
    443
    Peter Remmers
    Jan 22, 2012
Loading...

Share This Page