I have the following class hierarchy:
IMyObject % common interface defining methods and properties (abstract properties are supported by MATLAB)
A < IMyObject
B < IMyObject
...
IMyObject should act as interface and if possible not contain code.
There are many classes (A,B,...) derived from IMyObject and 90% of those share code for certain methods.
The straight forward way is to use an abstract class rather than an interface and just define all this code in IMyObject (possible renaming it to MyObjectRoot, MyObjectMaster, AbstractMyObject or similar). The 10% which do not share code of the mentioned methods would overwrite them.
However, I would like to have an explicit interface class (to separate the interface from code).
I use a "programming language" that supports multiple inheritance (MATLAB).
Now I may use the approach to create a class MyObject_GenericCode and the 90% classes would not only inherit from IMyObject but also from the MyObject_Generic class.
Since this generic class need access to the data (the abstract properties from IMyObject), they would also need to be derived from it.
Example:
MyObject_GenericCode < IMyObject
...
% the 90% classes having some kind of common code:
A < IMyObject & MyObject_GenericCode
B < IMyObject & MyObject_GenericCode
....
% 10% just use the interface and implement everything ob their own
Z < IMyObject
The problem is the diamond problem - but it's more theoretic in this case because I think there would not be such cases.
Apart from that - is there anything discouraging about that?
Finally, I found out that in MATLAB I can avoid this because the generic code classes do not need to be inherited from IMyObject but can still access the properties from the supplied object.
Example:
classdef IMyObject
properties (Abstract)
Fc;
end
methods (Abstract)
test(this);
end
end
classdef MyObject_GenericCode
methods
function test(this)
fprintf(1, 'Value of Fc: %d\n', this.Fc);
end
end
end
classdef A < IMyObject & MyObject_GenericCode
properties
Fc;
end
methods
function this = A()
this.Fc = 999;
end
end
end
myObj = A();
myObj.test();
which returns
Value of Fc: 999
without error. Although this works it sounds a bit "fishy" to me.
Which way is the appropriate option?
There is no need to use multiple inheritance in your case. Matlab's OOP does not have explicit interface classes, but if a class only consists of abstract methods and properties, in effect it acts like an interface. Generic class may implement a part of that interface, leaving some methods/properties abstract, to be implemented by a subclass.
So your hierarchy could look like this:
classdef IMyObject
properties (Abstract)
Fc;
end
methods (Abstract)
test(this);
end
end
classdef MyObject_GenericCode < IMyObject
properties (Abstract)
Fc;
end
methods
function test(this)
fprintf(1, 'Value of Fc: %d\n', this.Fc);
end
end
end
classdef A < MyObject_GenericCode
properties
Fc;
end
methods
function this = A()
this.Fc = 999;
end
end
end
Related
I have this
classdef what
properties ( ... )
...
end
methods (Access=public)
...
end
methods
function obj = what(...) ... end % constructor
function test = Test1() ... end
function test = Test2() ... end
end
The constructor has a lot of constraints in it such that when I create the what it fails if the conditions are not met, the constraints are tested by calling Test1 and Test2.
I have stored the test functions also under methods, and I want these to be hidden so that they don't show up outside the classdef. but I get thrown an error for Test1 and Test2.
I want these Test functions to be private, hidden, and only related to this class but I also want it to be call-able when using the constructor function found in methods, My question is: what would be the 'correct' place and method to store these functions.
I am currently getting an error when I use the constructor function, however, if I add the functions in the bottom of the page outside the classdef then the functions work but I am not sure if this is good practice and why I can't have the test functions in the method section.
There are several ways to deal with this.
In general, private functions are placed inside a methods (Access = private) block. Sometimes they can also be made static, if this makes sense. Private methods can also be placed in a separate folder.
classdef what
methods % no properties here
function obj = what(varargin) % constructor
...
out = obj.Test1(in); % object method calling example
...
end
end
methods (Access = private)
function tf = Test1(varargin)
...
end
% etc ...
end
If these functions are only ever used by the constructor, you can make them nested:
classdef what
methods % no properties here
function obj = what(varargin) % constructor
...
out = Test1(in); % no need for "obj" here
...
function tf = Test1(varargin)
...
end % Test1
end % constructor
end % methods
As mentioned by Cris, you can also put functions after the classdef block:
classdef what
...
end
function tf = Test1(varargin)
end
The suggestions above should solve your problem. Now for some other comments:
It's probably not a goot idea to name your class what, as this is a name of a builtin MATLAB function.
While it is possible to set a private method block to be Hidden, this is generally not needed in order to "hide" private methods, as these are not visible outside the class anyway.
I would personally suggest sticking to a certain naming convention (e.g. Pascal or Java) (this is referring to the class name which is lowercase as opposed to the "Test" methods which are uppercase).
If you're fairly new to MATLAB OOP, you might want to read about Handle Classes.
I'm new to MATLAB OOP. I have an abstract class defining an abstract method in my matlab path. I have a subclass named SubAbsClass in a subfolder named #SubAbsClass. I cannot create an object of the subclass after implementing the abstract method in the subclass. Here's my SubAbsClass implementation:
classdef SubAbsClass < AbsClass
properties
O1
end
methods
function obj=SubAbsClass(a,b)
obj.O1=absMethod(a,b);
end
end
methods (Static)
function out = absMethod(a,b)
out = a + b;
end
end
end
and my abstract class implementation is:
classdef AbsClass
methods(Abstract, Static)
result = absMethod
end
end
when I try to create an object in the MATLAB path (the abstract class is in the MATLAB path), I get an error. I have tried many configurations and searched the matlab oop document, and also the web including stackoverflow but unfortunately couldn't find an example to implement. I appreciate your help
>> clear all; clear classes;
>> obj=SubAbsClass(5,2)
Undefined function 'absMethod' for input arguments of type 'double'.
Error in SubAbsClass (line 11)
obj.O1=absMethod(a,b);
Within a method, Matlab considers non-dot references to be calls to local functions (defined outside the classdef block within the class file) or to a function somewhere on the Matlab path following the usual look-up rules.
So you need to call the Static method via the instance obj in the constructor:
methods
function obj = SubAbsClass(a,b)
obj.O1 = obj.absMethod(a,b);
end
end
One little caveat to the above is that non-Static methods also have a functional form.
So if the method was not Static, this notation would also work
methods
function obj = SubAbsClass(a,b)
obj.O1 = absMethod(obj,a,b);
end
end
Which, I think, is almost equivalent to the dot notation, although it has been said to be "generally" faster (albeit, that was four years ago).
Here are the details for ordinary method invocation and Static method invocation.
We have the abstract attribute of methods and properties in MATLAB R2014b, and I know the purpose of abstract attribute for methods. We can call functions in that method and define it in the superclass of a class. What I'm confused about is the purpose of the abstract attribute for a property in MATLAB. How do we use this?
The purpose of abstract properties (and abstract methods) is to allow the creation of interfaces:
The basic idea of an interface class is to specify the properties and methods that each subclass must implement without defining the actual implementation.
For example, you can define an abstract Car with the definition
classdef (Abstract) Car
properties(Abstract) % Initialization is not allowed
model
manufacturer
end
end
The abstract properties model and manufacturer cannot be initialized (that would be like instantiating an abstract class) and all classes that inherit from Car must specify their value for the subclass to be concrete.
If the properties were not abstract, the subclass would simply inherit them.
Making the properties abstract forms a contract of sorts that says "for you to be a usable (concrete) car you must have a model and manufacturer defined".
Therefore, in the definition
classdef FirstEveryManCar < Car
properties
model = 'T';
manufacturer = 'Ford';
end
end
the property definitions are compulsory for the class to not be made abstract automatically (which you could do if you have long class hierarchies).
There is a significant consequence for setter/getter methods (i.e. set.Property & get.Property).
Due to the way Matlab works, you can only implement setter/getter methods inside the class definition file of the class that declares the property. Therefore if you want to ensure a property is defined in the interface, but require implementation specific setter/getter methods, then declaring the property Abstract in the interface class ensures the subclass redefines the property and enables that class to define its own setter/getter methods.
Example 1 (Does not work)
Superclass
classdef (Abstract) TestClass1 < handle
properties
Prop
end
end
Subclass
classdef TestClass2 < TestClass1
methods
function obj = TestClass2(PropVal)
if nargin>0
obj.Prop = PropVal;
end
end
function set.Prop(obj, val)
if ~isnumeric(val)
error('Not a number!');
end
obj.Prop = val;
end
end
end
Example 2 (The correct way)
Superclass
classdef (Abstract) TestClass1 < handle
properties (Abstract)
Prop
end
end
Subclass
classdef TestClass2 < TestClass1
properties
Prop
end
methods
function obj = TestClass2(PropVal)
if nargin>0
obj.Prop = PropVal;
end
end
function set.Prop(obj, val)
if ~isnumeric(val)
error('Not a number!');
end
obj.Prop = val;
end
end
end
I don't know any example where you really need it, but it is typically used when a abstract superclass uses properties without having a reasonable default. This is a extremely trimmed down example, but imagine welcome implementing a full user interface while welcomeGer fills all required properties to provide it in german language:
%welcome.m
classdef welcome
properties(Abstract)
text
end
methods
function printText(obj)
disp(obj.text)
end
end
end
%welcomeGer.m
classdef welcomeGer<welcome
properties
text='Willkommen in unserem Hotel'
end
end
Alternative you could skip the definition of text at all, but then matlab would not throw an error when you forget to initialize text
I have the following problem. I have three classes: A, B, and C. A is the base class, B inherits A, and C inherits B.
Each has a constructor that takes in alot of arguments. However, the constructor for B does a few steps that I don't want in C that I can't undo unless I add more interface code, which would break encapsulation for a few variables. Namely, I'd give the user of my class the ability to change a few variables that I don't want them to.
As a result, I thought that I'd be clever and try to call the constructor of A from C. However MATLAB doesn't like this. See code below.
classdef C < B
% properties go here
% ...
methods(Access = public)
function obj = C(arguments)
obj = obj#A(A's arguments); % MATLAB doesn't like this
% ...
end
end
So, how can I (or can I not), call the constructor to A?
the constructor for B does a few steps that I don't want in C
In that case, your C is not an B. If the constructor from B is not executed in the construction process of C, then C cannot be a valid object of class B. However, the inheritance relationship implies this.
As such, the inheritance C < B is wrong. You should inherit C from A.
If you really want to, I'd try to implement a (mostly empty) protected constructor in B that is then called from C. Not entirely sure that works in Matlab though.
I have had trouble finding help in the matlab documentation and previous questions about using matlab inheritance and class constructors to make an interface. To make it tidy, within a package.
Instead of dragging through my code I can condense it as follows:
A package +MyPkg has a superclass Super and a few subclasses Sub1 Sub2... Most of my properties and methods are defined in Super such that Sub1 and Sub2 really only exist to use their constructors for simple routines or perhaps a few methods overloaded from Super.
So how do I go about writing the classdefs and constructors to support an interface where I can use the following calls:
a = MyPkg.Super(args).Sub1(args)
b = MyPkg.Super(args).Sub1(args).Sub1Method
In this case I want to keep arguments related to Super apart from arguments related to Sub1 for readability and organization.
Questions are welcome.
EDIT:
After considering the accepted answer below and some browsing I reached the conclusion that the interface shown above is not really in the spirit of OO and, for my data analysis application of it a more proper way to approach it would consist of a handle class with a constructor that populates an object or cell array of object properties. Because the class is a handle class one can then use the methods on it to produce desired methods. i.e. the following
% in +MyPkg\
classdef Super < handle
properties
outputArray
end
methods
function self = Super(args)
self.outputArray=load_values(args);
end
function out = do_analysis(self,params)
% do some analysis
end
end
end
Then to use this:
data1 = MyPkg.Super(args)
% Populate the outputArray
analysis1 = data1.do_analysis(params)
etc.,
Hope that helps someone else dealing with these issues
With respect to your question, you can't if you use inheritance. Only direct superclass constructors can be called from subclasses and only from the subclass can you call the superclass constructor. Ref.
Exposing the superclass like that really breaks the fundamentals of inheritance. Maybe ou should be thinking of another model, maybe composition ("has a" instead of "is a"), if you need that kind of access?