Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interface as a capability or Interface as a Type

Suppose I have such requirement:
The objects in the system all derive from a base class named IObject, and it may have objects with color, objects with transformations, and both.

Now there are 2 approach to design the class hierarchy.
The first one is:

just let concrete class derived from IObject, and also select "capability" interfaces as its base class to indicate it support such behavior, like interface: IHasColor,
IHasTransformation

The second one is:

Organize the base classes, and let concrete classes derived from one of them: IObject, IColorObject, ITransfromationObject , IColorAndTransformationObject

I prefer the first one (Does it have a formal name? ) as it is more flexible, and as you can see the second one may have class combination explosion problem when there are many attributes like color, transformation...

I would like to know your ideas and suggestions.

Thanks.

like image 800
Baiyan Huang Avatar asked Jun 22 '11 06:06

Baiyan Huang


People also ask

What does interface capability mean?

The ability to interface with a communication network for the purpose of communicating data to or from an IoT device. A network interface capability allows a device to be connected to and use a communication network.

Can interface be used as a type?

When you define a new interface, you are defining a new reference data type. You can use interface names anywhere you can use any other data type name.

WHAT IS interface and type of interface?

(n.) A boundary across which two independent systems meet and act on or communicate with each other. In computer technology, there are several types of interfaces. user interface – the keyboard, mouse, menus of a computer system. The user interface allows the user to communicate with the operating system.

What does type interface mean?

An interface type is an abstract tagged type that provides a restricted form of multiple inheritance. A tagged type, task type, or protected type may have one or more interface types as ancestors.


2 Answers

Classes abstract the real concept of types of objects.

Interfaces abstract the real concept of behaviors or abilities for an object.

So the questions becomes, is the "color" a property of the object or is it a capability of the object?

When you design a hierarchy you are constraining the world into a narrower space. If you take the color as a property of the object then you will have two kind of objects, the ones that have colors and the ones that do not. Does that fit your "world"?

If you model it as a capability (Interface) then you'll have objects that are able to provide, lets say cast, colors to the world.

For the transformation the same logic applies. You can either split the world into two kind of objects, the ones who can transform and the ones who can not, or you can view it as a capability, an object may have the ability to transform itself into another thing.

For me, from that point of view, what would make sense would be:

  • Color is a property of the object. In fact every object should have a color, even if its transparent, even if is reflection, even if its "none" (good luck figuring out what an object with color = none means in the real world, still it might make sense in your program logic).
  • Transformation is a capability, that is, an interface, something the object is capable of doing, among other things the object may or may not be able of doing.
like image 100
Jorge Córdoba Avatar answered Oct 05 '22 23:10

Jorge Córdoba


I'm working on classes hierarchy in my project and basically I have similar situation like you described in your question.

Let's say I have base type Object which is absolute root of all other classes in my toolkit. So naturally everything derives from it directly or through it's subclasses. There is a common functionality that every Object-derived class has to provide but in some leaf classes effects are little different than in others. For example every object have size and position which can be changed with properties or methods like Position = new Point(10, 10), Width = 15, etc. But there are classes that should ignore setting of a property or modify it according to self inner state. Think about control docked to left side of parent window. You can set Height property all you like but it will be generally ignored because this property really depend on Height of parent container control (or it's ClientArea height or sth like that).

So having Object abstract class implementing basic common functionality is ok until you reach a point of where you need "customize" behavior. If Object provides protected virtual SetHeight method that is called in setter of Height property you can override it in you DockedControl class and allow change of height only if docking is None, in other cases you limit it or ignore completely.

So we are happy but now we have requirement for object that react on mouse events like Click or Hover. So we derive MouseAwareObject from abstract Object class and implement events and stuff.

And now client want dockable, mouse aware objects. So we derive from DockableObject and... hmm, what now? If we can do multiple inheritance we can do it but we hit diamond problem with ambiguity of duplicated interface and we need to deal with it. We can have two memeber of Dockable and MouseAware types in new class and proxy external calls to them to provide functionality.

And last thing that comes to mind is to make IDockable and IMouseAware interfaces and let them define functionality and add them freely only to objects that need to deliver concrete behaviors/implementations.

I think I will split my base class into parts and leave my Object with very limited "core" set of properties and methods and rest of functionality that is in fact optional to Objects as a type but needed in concrete cases move to interfaces like IResizable, IDockable, IMakeAWorldABetterPlaceAble, etc. With this solution it is possible to "attach" behaviors to Object-derived classes without need for draggin virtual or pure virtual (abstract) methods from root base class all the way down to leaf class.

There is of course inconvenience of implementing interfaces in all affected classes but you can always implement some "adapters" and just forward calls to them. That way you don't have duplicated implementation (to some extend of course) and have decoupling between realization of task (Resize can mean different things for different classes) and expectation of client code.

Probably this is not ideal answer for your question but maybe it will hint you to your own solution.

like image 34
grapkulec Avatar answered Oct 06 '22 00:10

grapkulec