How to hide implementation details?

I

Immortal Nephi

I want to create an interface of a door. The client is able to see
the implementation behind the interface because inheritance is
present. The code is stored in the header. How do I hide the
implementation?
A door is an abstraction of a particular arrangement of a rectangular
piece of material with hinges and a doorknob. It has four routines of
Open(), Close(), isOpened(), and isClosed().
And the doorknob is in turn an abstraction of a particular formation
of brass, nickel, iron, or steel. It has four routine of Lock(),
Unlock(), IsLocked(), and IsUnlocked().
And also, Color_Knob is in turn an abstraction of some colors.
How do I put three objects of Door, Knob, and Color_Knob together
into a function or another class. Is it the way how design looks
good?
The inheritance does not make any sense, but it should be
composition. Open() and Close() belongs to Door and they have no
reasons to be inherited into doorknob class nor color_knob class.
Also, Lock() and Unlock() belongs to doorknob class and should not be
inherited into color_knob.
Should knob_door and color_knob objects be created into memory and
place them in Door class like composition?

For example:

/* Header Door.h */

class Door
{
public:
Door() {}
virtual ~Door() {}
virtual void Open() {}
virtual void Close() {}
virtual bool IsOpened() { return m_door; }
virtual bool IsClosed() { return !m_door; }

private:
bool m_door;
};

class Knob : public Door
{
public:
Knob() {}
virtual ~Knob() {}
virtual void Lock() {}
virtual void Unlock() {}
virtual bool IsLock() { return m_Knob; }
virtual bool IsUnlocked() { return !m_Knob; }

private:
bool m_Knob;
};

class Color_Knob : public Knob
{
public:
Color_Knob() {}
virtual ~Color_Knob() {}

void Select_Brass() { color = Brass; }
void Select_Nickel(){ color = Nickel; }
void Select_Iron(){ color = Iron; }
void Select_Steel(){ color = Steel; }
bool IsBrass() { return color == Brass; }
bool IsNickel() { return color == Nickel; }
bool IsIron() { return color == Iron; }
bool IsSteel() { return color == Steel; }

private:

enum Color
{
Brass,
Nickel,
Iron,
Steel
} color;

Color Get_Color() { return color; }
};

#include “Door.h”

int main()
{
Color_Knob color_knob;
Knob knob;
Door door;

color_knob.Select_Brass();

bool bColor;
bColor = color_knob.IsBrass();
bColor = color_knob.IsIron();

door.Close();
knob.Lock();

return 0;
}
 
P

Puppet_Sock

        I want to create an interface of a door.
[snip]

Um. And this isn't homework?
 The client is able to see
the implementation behind the interface because inheritance is
present.  The code is stored in the header.  How do I hide the
implementation?

"But doctor! Doctor! It hurts when I do this!"
"Well, then, don't do that."

Don't put the implementation in the header file unless
there is a good reason for it. Some template stuff has
to go in the header, for example. I don't *see* any
templates in your files.
        A door is an abstraction of a particular arrangement of a rectangular
piece of material with hinges and a doorknob.  It has four routines of
Open(), Close(), isOpened(), and isClosed().

Ok. It seems like a pretty early stage in your class. Hmm...
May the 26th. Summer school has started?
        And the doorknob is in turn an abstraction of a particular formation
of brass, nickel, iron, or steel.  It has four routine of Lock(),
Unlock(), IsLocked(), and IsUnlocked().

As Daniel T said, this does not really work very well.
A door knob isn't a door, it's part of a dor. It does
not make a lot of sense to inherit here.

Possibly you might want door and knob to inherit from
some other class. Something like "stuff from the hardware
store" or something like that. Look up the factory idiom
to see why that *might* make sense.
        And also, Color_Knob is in turn an abstraction of some colors.
        How do I put three objects of Door, Knob, and Color_Knob together
into a function or another class.  Is it the way how design looks
good?
        The inheritance does not make any sense, but it should be
composition.  Open() and Close() belongs to Door and they have no
reasons to be inherited into doorknob class nor color_knob class.
Also, Lock() and Unlock() belongs to doorknob class and should not be
inherited into color_knob.

So, you already know it does not make sense. Ok.
        Should knob_door and color_knob objects be created into memory and
place them in Door class like composition?

That's one way. How you choose to combine functionality
of different parts of a problem will depend on context.
Does your application require to be able to have a door
as an object, and a knob as an object, as separate things?
That is, can you have a door with no knob? Can you have
a knob with no door? If you can, can they go together
after you make them? So, is it a door factory or some
such thing that you are running here? Or is it one or
more rooms with doors all set and just opening, closing,
locking, unlocking, etc.? That is, do you want to change
door configuration (knob, no knob, colour, no colour,
etc.) or not?

If you are never going to create doors except with knobs
already there, then maybe you don't want a separate
knob type at all. If you are going to be swapping knobs
in and out, maybe you want composition with the knob
being pointed at by a member pointer rather than as
a member object. Then you could have polymorphism on
knob type.
For example:

/* Header Door.h */

class Door
{
public:
        Door() {}
        virtual ~Door() {}
        virtual void Open() {}
        virtual void Close() {}
        virtual bool IsOpened() { return m_door; }
        virtual bool IsClosed() { return !m_door; }

private:
        bool m_door;

};

Yeah. If you care about this implementation being visible,
then you put it in the source file (.cpp or .c++ or
..cxx or whatever your compiler calls it.) If you are
wanting to make the variables not visbible from the
header file the client sees, then look up the "pointer
to implementation" idiom. It's allso called PImpl.

Also, m_door is a poor name. What about the door does
it contain? Maybe change that to something like m_isOpen
or something.
class Knob : public Door

We already talked about inheritance here.

Public inheritance is usually easiest to get right if
you use the substitution principle. If childClass
inherits from parentClass, then you should be able
to use an instance of childClass whenever an instance
of parentClass is required.

Can you proffer up a knob whenever a door is required?
Probably not.

Just to shake you up a bit, consider it the other way.
Can you proffer up a door whenever a knob is required?
Hmmm... In some contexts, if doors *always* have knobs,
then maybe you can. So maybe you can inherit the other
way, door from knob. Though, in most contexts, that
is going to be pretty bad.
{
public:
        Knob() {}
        virtual ~Knob() {}
        virtual void Lock() {}
        virtual void Unlock() {}
        virtual bool IsLock() { return m_Knob; }
        virtual bool IsUnlocked() { return !m_Knob; }

private:
        bool m_Knob;

};

class Color_Knob : public Knob
{
public:
        Color_Knob() {}
        virtual ~Color_Knob() {}

        void Select_Brass() { color = Brass; }
        void Select_Nickel(){ color = Nickel; }
        void Select_Iron(){ color = Iron; }
        void Select_Steel(){ color = Steel; }
        bool IsBrass() { return color == Brass; }
        bool IsNickel() { return color == Nickel; }
        bool IsIron() { return color == Iron; }
        bool IsSteel() { return color == Steel; }

Ick. Next week you will want to add glass knobs.
Or fake ivory ones that are made of plastic.
And you will need to write new functions and
recompile the code to do it. Or brass knobs will
go out of style or something, and you will have
to remove those functions.

This is an example of where you probably want
stuff about the class to be visible.
private:

        enum Color
        {
                Brass,
                Nickel,
                Iron,
                Steel
        } color;

        Color Get_Color() { return color; }

This enum should probably be available to any client.
And you should just have one setcolour function and
one getcolour function.

Or you could have the colours as items in a config
file that can be modified without changing the code.
Then you could read in the list of colours that are
available at the store (factory, etc.) Store them in
a vector of some kind.

Context, always context. How likely is it that next
week you will have a different set of colours for
doors or knobs?

[rest snipped]
Socks
 
I

Immortal Nephi

On May 25, 10:33 pm, Immortal Nephi <[email protected]>
wrote:>         I want to create an interface of a door.

[snip]

Um. And this isn't homework?

No, homework does not exist. Every reader is aware what my post was
said in the past. I learn independently doing self-study at home.

Every time, I post class example. They always said bad design. I
could not find any good book to explain how to do good design. I
found old post when someone posted to say how to break giant class
into pieces of classes.

They suggested a book. The second edition book’s title is Code
Complete and author’s name is Steve McConnell. I bought it from
Amazon. I spent all day reading Chapter 5 – Design and Construction
and Chapter 6 – Working Classes. That book is very interesting.
 The client is able to see

"But doctor! Doctor! It hurts when I do this!"
"Well, then, don't do that."

Don't put the implementation in the header file unless
there is a good reason for it. Some template stuff has
to go in the header, for example. I don't *see* any
templates in your files.

You are right. The client is able to see private data members and
private member functions in the class in header. The class should be
interface. I talk about abstraction and inheritance hierarchy.
Ok. It seems like a pretty early stage in your class. Hmm...
May the 26th. Summer school has started?

No summer school like I said before.
As Daniel T said, this does not really work very well.
A door knob isn't a door, it's part of a dor. It does
not make a lot of sense to inherit here.

Possibly you might want door and knob to inherit from
some other class. Something like "stuff from the hardware
store" or something like that. Look up the factory idiom
to see why that *might* make sense.


So, you already know it does not make sense. Ok.

I did not say very clear. House is an abstraction. You write “class
house”. How do you break complexity into simple code? You need to
divide or decompose house into several classes.
Several classes are derived from house, which is called windows,
doors, siding, wiring, plumbing, insulation, etc. I focus to
decompose door class. Knob class is derived from door class. Colored
knob class is derived from knob class.
I hope that you know what I mean. I talk about decomposing classes.
You can notice Lock() and Unlock() are in knob class and should not be
inherited into colored knob class. Also, Open() and Close() from door
class should not be inherited into knob class.
I guess you are suggesting not to use inheritance hierarchy. Then,
write two base classes of knob and colored knob. Put them into door
class as composition.
Do you understand what I am saying?
That's one way. How you choose to combine functionality
of different parts of a problem will depend on context.
Does your application require to be able to have a door
as an object, and a knob as an object, as separate things?
That is, can you have a door with no knob? Can you have
a knob with no door? If you can, can they go together
after you make them? So, is it a door factory or some
such thing that you are running here? Or is it one or
more rooms with doors all set and just opening, closing,
locking, unlocking, etc.? That is, do you want to change
door configuration (knob, no knob, colour, no colour,
etc.) or not?

If you are never going to create doors except with knobs
already there, then maybe you don't want a separate
knob type at all. If you are going to be swapping knobs
in and out, maybe you want composition with the knob
being pointed at by a member pointer rather than as
a member object. Then you could have polymorphism on
knob type.












Yeah. If you care about this implementation being visible,
then you put it in the source file (.cpp or .c++ or
.cxx or whatever your compiler calls it.) If you are
wanting to make the variables not visbible from the
header file the client sees, then look up the "pointer
to implementation" idiom. It's allso called PImpl.

Yes, I know what you mean. It is called private implementation. It
is annoying to create private implementation in **each classes**.
Maybe, you are suggesting let create interface in header and
implementation in source code.
After you put all headers and source codes into package, you create
package interface and private implementation. It becomes to be the
component library. The client will only see interface when they
include header into their code.

Also, m_door is a poor name. What about the door does
it contain? Maybe change that to something like m_isOpen
or something.
class Knob : public Door

We already talked about inheritance here.

Public inheritance is usually easiest to get right if
you use the substitution principle. If childClass
inherits from parentClass, then you should be able
to use an instance of childClass whenever an instance
of parentClass is required.

Can you proffer up a knob whenever a door is required?
Probably not.

Just to shake you up a bit, consider it the other way.
Can you proffer up a door whenever a knob is required?
Hmmm... In some contexts, if doors *always* have knobs,
then maybe you can. So maybe you can inherit the other
way, door from knob.  Though, in most contexts, that
is going to be pretty bad.




{
public:
        Knob() {}
        virtual ~Knob() {}
        virtual void Lock() {}
        virtual void Unlock() {}
        virtual bool IsLock() { return m_Knob; }
        virtual bool IsUnlocked() { return !m_Knob; }
private:
        bool m_Knob;

class Color_Knob : public Knob
{
public:
        Color_Knob() {}
        virtual ~Color_Knob() {}
        void Select_Brass() { color = Brass; }
        void Select_Nickel(){ color = Nickel; }
        void Select_Iron(){ color = Iron; }
        void Select_Steel(){ color = Steel; }
        bool IsBrass() { return color == Brass; }
        bool IsNickel() { return color == Nickel; }
        bool IsIron() { return color == Iron; }
        bool IsSteel() { return color == Steel; }

Ick. Next week you will want to add glass knobs.
Or fake ivory ones that are made of plastic.
And you will need to write new functions and
recompile the code to do it. Or brass knobs will
go out of style or something, and you will have
to remove those functions.

This is an example of where you probably want
stuff about the class to be visible.


        enum Color
        {
                Brass,
                Nickel,
                Iron,
                Steel
        } color;
        Color Get_Color() { return color; }

This enum should probably be available to any client.
And you should just have one setcolour function and
one getcolour function.

Or you could have the colours as items in a config
file that can be modified without changing the code.
Then you could read in the list of colours that are
available at the store (factory, etc.) Store them in
a vector of some kind.

Context, always context. How likely is it that next
week you will have a different set of colours for
doors or knobs?

[rest snipped]
Socks- Hide quoted text -

- Show quoted text -- Hide quoted text -

- Show quoted text -
 
L

LR

Immortal said:
I want to create an interface of a door. The client is able to see
the implementation behind the interface because inheritance is
present. The code is stored in the header. How do I hide the
implementation?
Composition.



/* Header Door.h */

class Door
{
public:
Door() {}
virtual ~Door() {}
virtual void Open() {}
virtual void Close() {}
virtual bool IsOpened() { return m_door; }
virtual bool IsClosed() { return !m_door; }

private:
bool m_door;
};

I don't think that in the usual case a Knob is-a Door.
class Knob : public Door
{
public:
Knob() {}
virtual ~Knob() {}
virtual void Lock() {}
virtual void Unlock() {}
virtual bool IsLock() { return m_Knob; }
virtual bool IsUnlocked() { return !m_Knob; }

private:
bool m_Knob;
};



Knob knob;
Door door;

A Door and a Knob that is-a Door, but the instance of Knob, knob isn't
at all related to the instance of Door, door.


door.Close();
knob.Lock();

What I'm really curious about is how you intend to use these classes.

Suppose that:
Door door;
door.Open();
const bool t = door.IsOpened();

What should those lines do if a Door has-a Knob and the Knob::IsLock()
would return true? What value will t have?

I think in someways the question "Should a Door have-a Knob?" is the
similar to "Is an ellipse a circle?" IMHO the best answer is, it depends
on how you want the classes to behave in the program you are creating.

Could your door have a handle instead of a knob? Or would a handle be a
kind of knob? Does the lock have to be part of the knob?

Or maybe you need something like:

class AssembledDoor {
Door door;
Knob knob;
....
};

LR
 
N

Nick Keighley

        I want to create an interface of a door.  
why?


The client is able to see
the implementation behind the interface because inheritance is
present.  The code is stored in the header.  How do I hide the
implementation?

Pimpl, Facade pattern, Factory pattern

        A door is an abstraction of a particular arrangement of a rectangular
piece of material with hinges and a doorknob.  It has four routines of
Open(), Close(), isOpened(), and isClosed().

is that all the client is supposed to see?

        And the doorknob is in turn an abstraction of a particular formation
of brass, nickel, iron, or steel.

can the client see this? If so how?

 It has four routine of Lock(),
Unlock(), IsLocked(), and IsUnlocked().

        And also, Color_Knob is in turn an abstraction of some colors.

what? What is an abstarction of colours? What is the relationship
between Knob and Color_Knob? Is a Color_Knob also a Knob. Or is Color
just an attribute of Knob?

        How do I put three objects of Door, Knob, and Color_Knob together
into a function or another class.  Is it the way how design looks
good?
        The inheritance does not make any sense, but it should be
composition.  

sounds reasonable

Open() and Close() belongs to Door and they have no
reasons to be inherited into doorknob class nor color_knob class.
Also, Lock() and Unlock() belongs to doorknob class and should not be
inherited into color_knob.

why not. Can't you unlock a coloured knob. If coulored knob can't do
things that knob can do then it shouldn't publicly inherit.

I can't see what coloured_knob is supposed to do
 
M

Michael Doubez

        I want to create an interface of a door.  The client is able to see
the implementation behind the interface because inheritance is
present.  The code is stored in the header.  How do I hide the
implementation?


I assume you mean that a specific implementation of the interface is
exposed.

You could look into creational patterns. For C++ there is the
compilation firewall idiom that allows you to expose an implementation
but hide the nitty gritty.

        A door is an abstraction of a particular arrangement of a rectangular
piece of material with hinges and a doorknob.  It has four routines of
Open(), Close(), isOpened(), and isClosed().

It could also be ajar :)
        And the doorknob is in turn an abstraction of a particular formation
of brass, nickel, iron, or steel.  It has four routine of Lock(),
Unlock(), IsLocked(), and IsUnlocked().
        And also, Color_Knob is in turn an abstraction of some colors.
        How do I put three objects of Door, Knob, and Color_Knob together
into a function or another class.  Is it the way how design looks
good?

[snip]

Redecomposing your design you have two abstraction:
- a Door (which could be a specific Gate abstraction) which handle a
state (opened/closed) and cab be operated (open/close). But
eventually, the closing or opening could fail. Keeping as close as
possible to your design, I could write it (with robust interface not
failing if by example I try to open door already opened):

class Door
{
public:
Door(bool is_open = false):m_is_open{}
virtual ~Door() {}

// return true upon success
bool Open()
{if(!m_is_open)m_is_open = tryOpenDoor();
return m_is_open; }
// return true upon success
bool Close()
{if(m_is_open)m_is_open = !tryCloseDoor();
return !m_is_open; }
bool IsOpened() const{ return m_is_open; }

protected: // real door implement opening/closing condition
// return true upon success
// pre Door is closed
virtual bool tryOpenDoor()=0;
// return true upon success
// pre Door is opened
virtual bool tryCloseDoor()=0;

private:
bool m_is_open;
};

Now, as others pointed out, for normal people a knob is not a door.
And it doesn't necessarily have a state. The only thing you know is
that is you want to open with it, it can grant you or not to open the
door. Lets keep it simple:
struct Knob
{
virtual ~Knob(){}
// return true upon success
virtual bool tryOpenWithKnob()=0;
// return true upon success
virtual bool tryCloseWithKnob()=0;
};

Now You can have a Knob with a Lock:
class KnobWithLock: public Knob
{
public:
KnobWithLock(bool is_locked)
: Knob()
, m_is_locked(is_locked){}

bool Lock()
{ m_is_locked = true; // easy lock
return m_is_locked;}
bool Unlock()
{ m_is_locked = false; // easy unlock
return m_is_locked;}
bool IsLocked () { return m_is_locked; }

virtual bool tryOpenWithKnob()
{ /* can open only if unlocked */
return !m_is_locked; }
virtual bool tryCloseWithKnob()
{ /* can always close */
return true; }
private:
bool m_is_locked;
};

Now if you want to make a door with a knob:

class DoorWithKnob: public Door
{
public:
DoorWithKnob(Knob* knob = NULL):m_knob(knob){}

Knob* knob()const{return m_knob;}

protected:
virtual bool tryOpenDoor()
{ // can open if no knob
return m_knob ? m_knob->tryOpenWithKnob() : true;
}
virtual bool tryCloseDoor()=0;
{ // can close if no knob
return m_knob ? m_knob->tryCloseWithKnob() : true;
}

private:
Knob* m_knob;
};

Now, concerning the colored knob. The color is in fact an attribute of
a Knob that doesn't modify it. You could use a kind of decoration:

template<class TKnobType>
class ColoredKnob: TKnobType
{
// ... code to handle color of knob
};

And you main program is:
int main()
{
ColoredKnob<KnobWithLock> knob;
DoorWithKnob door(&knob);

knob.Select_Brass();

knob.Unlock();
door.Open();
knob.Lock();
door.Close();

return 0;
}
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top