views:

34

answers:

2

Short question

I have one C++ domain model. It has some methods used by the internal API as well as other public methods. I don't want to expose those API methods. I'm thinking of using the proxy pattern to hide those methods. Do you think this is a good idea? Is there some design pattern to achieve this?

Long example

Let's say there's a robotic arm in some remote location that can be controlled by the software but can also be manually moved by some technician. It has some sensors that allow it to know which kind of object it is holding. In my proyect it's something completely different but I use this just as an example. So I'd have one RoboticArm class which contains a RoboticHeldObject abstract class. RoboticArm let's you know which RoboticHeldObject it is holding, appart from letting you move the arm. However, you can't decide to pickup and release an object. This is decided by a technician operating the robot. So it would be something like:

---------------------------------------------
RoboticArm
---------------------------------------------
+ heldObject()             RoboticHeldObject*
+ moveUp()
+ moveDown()
+ releaseObject()
+ holdObject(RoboticHeldObject*)
---------------------------------------------
- heldObject               RoboticHeldObject*
- service                  RobotService

Since the implementation is quite complex, I use an external class, RobotService which actually performs the hard work. However, it's not an Anemic Domain Model since it's RoboticArm who actually uses RobotService (thus has functionality) and the rest of the world doesn't know anything about RobotService.

The question here is: releaseObject() and holdObject() are API methods here used by RobotService only. They are called only by RobotService whenever a technician releases the object being hold by the arm or places a new object. Thus, they are called when some network event is handled by RobotService (remember the arm is in a remote location, so events are received through a network). For example:

RobotService::handleObjectReleaseEvent(event)
{
 RoboticArm *arm = correspondingRoboticArm(event);
 arm->releaseObject();
}

My approach

To hide those methods, I would rename RoboticArm to RealRoboticArm and create a RoboticArm proxy class:

---------------------------------------------
RoboticArm        (the proxy)
---------------------------------------------
+ heldObject()             RoboticHeldObject*
+ moveUp()
+ moveDown()
---------------------------------------------
- realArm                  RoboticArm*



---------------------------------------------
RealRoboticArm    (the real object)
---------------------------------------------
+ heldObject()             RoboticHeldObject*
+ moveUp()
+ moveDown()
+ releaseObject()
+ holdObject(RoboticHeldObject*)
---------------------------------------------
- heldObject               RoboticHeldObject*
- service                  RobotService

Since RoboticArm is a proxy, RoboticArm::heldObject() would call realArm->heldObject(), RoboticArm::moveUp() realArm->moveUp() and so on.

The RobotService would have a pointer to the RealRoboticArm instance, so it could call the API methods such as releaseObject(). However, other parts of the application would only be able to use the methods in RoboticArm, since they don't have a pointer to RealRoboticArm. Thus releaseObject() and holdObject() would be effectively hidden from the audience.

The question

I am not 100% sure if this is the proxy pattern or the adapter pattern. Do you think this is a proper way to model such system? Is there a better pattern?

A: 

It is common to have classes which do the same thing, but on different levels of abstraction.

Example, in decreasing levels of abstraction:

  • GrabbingRobot.GrabBottle();
  • SpaciousRobotArm.MoveToCoordinates(x, y);
  • RobotBase.Turn(degrees), RobotArm.Extend(inches)
  • RobotElbow.Bend(degrees)
  • RobotServoMotor.Turn(cycles)
  • RobotServoRelais.TurnOn(seconds)

In your example, RoboticArm has abstracted the holding of things out of RealRoboticArm. Instead of setting and releasing things, the RoboticArm magically knows whether it is holding something and what it is holding. This is neither Proxy nor Adapter.

There is no sufficient elaborate permissions structure to prevent GrabbingRobot from calling RobotElbow directly.

Sjoerd
So this is not a design pattern, just an abstraction, ok.Do you think I shouldn't abstract setting and releasing things from the public API at all?As I exposed, the object the arm is holding might be changed outside of the control of the application. So from the point of view of the RoboticArm this would happen magically since it didn't do anything. The object would just get "notified" of a change by the service, which is who received the corresponding network event.Thanks.
A: 

You can solve your problem using interfaces. You have one object, RobotArm, which implements two interfaces: one for the API and one for the using class.

The using class will use its interface, the one without the API methods, and thus can not call the API methods.

Sjoerd
Keep in mind it's C++, not Java. I would have to use double inheritance for this, e.g. "class IRobotArm", "class IRobotArmPrivateApi" and "class RobotArm : public IRobotArm, public IRobotArmPrivateApi". I prefer to avoid double inheritance unless strictly necessary. Anyway, it would be possible for the using class to cast an interface pointer to the subclass that implements it. Example: dynamic_cast<RobotArm*>(iRobotArmInstance)->releaseObject().