Jump to content

Strategy Pattern


Recommended Posts

I'm slowly learning OOP and have tons of questions!

I've seen three or four mentions of the Strategy pattern on here, but no concrete discussions of how it should be implemented in LVOOP. I gave it a try using Daklu's interface framework here, and attached to this post is another attempt using only native LVOOP features. In the native LVOOP project, I used a parent class to dispatch the algorithms since interfaces aren't natively available. I can only see two downsides to doing it this way, though:

  1. Every algorithm's must be a descendant of the "aAlgorithm" class.
  2. I noticed that requesting a method that doesn't exist in the concrete implementation ("Algorithm2:Method3.vi") results in the parent method executing instead. That could be a pain in the rear, I guess.

Are there other detriments I'm not noticing? I feel like I could work around those two pretty easily in most situations.

NOTE: attachment is LV 9.0.1

Strategy Pattern (LVOOP core).zip

Edited by Stobber
Link to comment

Are there other detriments I'm not noticing? I feel like I could work around those two pretty easily in most situations.

This is a ByVal pattern I use a lot and normally I don't find the workarounds that bad for the way you have mentioned implementing it:

For point 1. I create an interface class for that algorithm.

To get around point 2. if I want, I can leave a parent interface method empty, so if it is not overridden - no dramas - it runs but nothing happens.

Mikael H also posted a ByRef implementation too on LAVA.

Link to comment

As you've no doubt discovered, OO terminology has slightly different meanings in Labview than in other languages. To aid discussion, here's how I think about some common terms:

abstract method - Text languages use the 'abstract' keyword to define methods that are defined, but not implemented. Labview doesn't have an abstract keyword, so an abstract method is simply a parent method that doesn't have any code on the block diagram. All your aAlgorithm methods are abstract.

abstract class - Text languages use the 'abstract' keyword to define classes that cannot be instantiated. In Labview it is impossible to create a type that cannot be instantiated. If it exists on the block diagram or front panel it will be instantiated at runtime. I use "abstract class" in Labview to refer to a class in which all the methods are abstract, like aAlgorithm. In my mind if any methods are implemented the class is no longer abstract. In text languages you cannot instantiate an abstract class. In Labview there is no reason to use an abstract class in your code other than as a type definition. (Don't confuse that with me saying there's no reason to have an abstract class in your project.)

interface - The generic term means pretty much the same thing in both Labview and text languages. Abstract methods and abstract classes are interfaces, but interfaces are not always abstract.

Interface (with a capital 'I') - These exist as a specific construct in text languages and have no native correlation in Labview. I use the term to refer to classes that derive from the IUnknown class in the Interface framework.

-----------------------

Your implementation seems to be quite reasonable, though strictly speaking I think it is closer to the template method pattern as defined by GoF than the strategy pattern; however, I'm not convinced these two patterns are actually different patterns and not just slight variations of the same thing.

One thing to consider is whether you need aAlgorithm in your hierarchy. I've found that usually using an abstract class is simply extra code, especially in a single-module application. Providing some sort of default implementation makes more sense to me in the context of data flow and reduces complexity. It also means I don't have to raise errors in each of the abstract class' methods just in case someone accidentally writes code that calls one. In your example I would consider replacing aAlgorithm with Algorithm 1.

That's not to say that I never use abstract classes. Suppose aAlgorithm defines 10 methods and each subclass implements a unique combination of 2 of them. If aAlgorithm provides a default implementation then your child classes not only have to override the abstract methods to provide an appropriate implementation but also have to override the parent's implemented methods to "blank" them. I've been down that path and thought it was more confusing. My current working rule of thumb is to use an abstract class when I expect child classes will need to blank a parent method. (I'll also use abstract classes across code module boundaries when a default implementation is meaningless, but that's a more complex use case.)

I don't think using Interfaces to implement the strategy pattern is a good idea in any language. Interfaces are best used to expose common behavior across otherwise unrelated classes. For instance, I could have a Dinosaur object, a SodaCan object, and a NetworkConnection object. If I want to save them all to disk it might make sense to create an ISerializable or IPersistable Interface class to implement that functionality. Strategy algorithms are related so using Interfaces is just extra work IMO.

If having all your algorithm classes derive from the same parent is a problem (perhaps your algorithms classes are already pre-defined) then using adapter classes is a better solution than Interfaces. The diagram below shows how that is implemented.

post-7603-087124100 1282751645_thumb.png

Incidentally, I haven't had a chance to look over your code on the other thread but it is on my to-do list.

-Dave

Link to comment

@Dave/Daklu, the Adapter seems to be a very cool pattern for LVOOP, as a kind of substitute for the missing interfaces. I'll need to study them...

Here a set of 'stupid' things (I just want to state that I'm not a wise old man but feel more like a babarian in the fine civilization of OOP) I gained from my studies on meta-modelling and OOP (just in case you might find them useful or like to discuss):

* It seems that in the beginning of OOP interfaces and abstract methods/classes were about the same. You call an object by its abstract parent class or it's interface and don't care how it implements it's methods. How these are implemented (not the methods but abstract c/m and interfaces) is very much a language flavour.

* In MOF (which is the metamodel of OOP), abstract classes are suggested like this (which is possible in LVOOP): Each package should provide a factory to return the classes. In case of an abstract class it should return a null-pointer (that's not possible in LV, but a default obj) and a NullPointerExeption.

* In uml, interfaces are very different to classes in respect of their inheritance. I'm not yet into the details. But it is mentioned that they provide a facade to the class, so the facade pattern could be a way to go (I think that's Daklu's implementation, I also think about the adapter pattern at the moment).

* In uml there is also another concept, I think it was called 'Substitutable'. It works like an interface in situation where you can't have interfaces (uml is meant to model also stuff outside programming; you can't model an electronic circuit by defining 'interfaces' the same way). Again, I haven't looked into the details.

Felix

Link to comment

Interesting insights Felix. You've done far more research into UML and generalized OOP than I have, so I'll defer to you on those topics.

@Dave/Daklu, the Adapter seems to be a very cool pattern for LVOOP, as a kind of substitute for the missing interfaces. I'll need to study them...

I use adapters all the time for my hardware abstraction layer. It allows me to create independent (derive from LVObject) and reusable device-specific classes for our instruments without having to try and fit instruments with different capabilities into the same class hierarchy. It does require a little more application-specific code and goes against our instinct to "reuse everything," but I've found it is far more flexible, easier to maintain, and easier to extend.

* It seems that in the beginning of OOP interfaces and abstract methods/classes were about the same. You call an object by its abstract parent class or it's interface and don't care how it implements it's methods. How these are implemented (not the methods but abstract c/m and interfaces) is very much a language flavour.

Do you mean when OOP programming first got started back in the 60's? I'm not sure I'm following your meaning.

* In uml, interfaces are very different to classes in respect of their inheritance. I'm not yet into the details. But it is mentioned that they provide a facade to the class, so the facade pattern could be a way to go (I think that's Daklu's implementation, I also think about the adapter pattern at the moment).

In the languages I'm familiar with Interfaces behave differently than classes so I guess it's not surprising UML treats them differently. An interface can be a facade (as defined by GoF,) but an Interface cannot. Facades provide a single simplified access point to a group of related classes that provide some functionality to the rest of the application. It allows the app-level code to only have to worry about the facade class instead of managing all of the classes that make up the subsystem. The Interface Framework follows the adapter pattern much more closely than the facade pattern.

* In uml there is also another concept, I think it was called 'Substitutable'. It works like an interface in situation where you can't have interfaces (uml is meant to model also stuff outside programming; you can't model an electronic circuit by defining 'interfaces' the same way). Again, I haven't looked into the details.

Be interesting to see if that's applicable to any LV concepts.

Link to comment

As you've no doubt discovered, OO terminology has slightly different meanings in Labview than in other languages. To aid discussion, here's how I think about some common terms:

abstract method - Text languages use the 'abstract' keyword to define methods that are defined, but not implemented. Labview doesn't have an abstract keyword, so an abstract method is simply a parent method that doesn't have any code on the block diagram. All your aAlgorithm methods are abstract.

abstract class - Text languages use the 'abstract' keyword to define classes that cannot be instantiated. In Labview it is impossible to create a type that cannot be instantiated. If it exists on the block diagram or front panel it will be instantiated at runtime. I use "abstract class" in Labview to refer to a class in which all the methods are abstract, like aAlgorithm. In my mind if any methods are implemented the class is no longer abstract. In text languages you cannot instantiate an abstract class. In Labview there is no reason to use an abstract class in your code other than as a type definition. (Don't confuse that with me saying there's no reason to have an abstract class in your project.)

interface - The generic term means pretty much the same thing in both Labview and text languages. Abstract methods and abstract classes are interfaces, but interfaces are not always abstract.

Interface (with a capital 'I') - These exist as a specific construct in text languages and have no native correlation in Labview. I use the term to refer to classes that derive from the IUnknown class in the Interface framework.

The use of these terms has been a matter of some confusion here as well.

abstract method--fully agree with Dave's definition. This corresponds with its usage in T. Budd, An Introduction to Object-Oriented Programming, 3d ed. In C++ this is apparently a pure virtual method. (I'm basing this on Budd, p. 170. I'm not a C++ guru.)

abstract class--C. Larman, Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development, 3d ed., defines this as "A class that can be used only as a superclass of some other class; no objects of an abstract class may be created except as instances of a subclass." That is how we use the term. What this means to us is: 1) we never instantiate an abstract class (just a restatement); 2) child classes override its methods (though it is not always necessary for every child to override every method), but the method definition in the abstract class may or may not be (in C++ terms) a pure virtual method--that is, it may have some common functionality that is called in the child implementations. This differs significantly from Dave's usage.

interface--Budd, p. 170, writes, "A class can have abstract (or pure virtual) methods and nonabstract methods. A class in which all methods were declared as abstract (or pure virtual) would correspond to the Java idea of an interface." This matches Dave's description of abstract class above; I prefer to reserve interface for this following Budd. (I guess this also means that all children must implement all the parent methods.)

The upshot: LabVIEW doesn't explicitly support the concepts of abstract classes or interfaces. We can approximate them by creating classes that fit the above definitions. In our implementations of the State Pattern (which has the same architecture as the Strategy Pattern) we define superstates that, of course, we never instantiate. (We only instantiate leaf classes, of course.) We do, however, allow for the methods on the superstate classes to include behavior common to their substates. (This makes sense, of course, because it means we don't duplicate the code unnecessarily.) Such a solution fits with the definition of abstract class from Larman I gave above, so we consider (in LabVIEW and in UML) such superstate classes to be abstract classes.

[Hmm... I see that in Head First Design Patterns the top-level State or Strategy class are interfaces, which means that the top-level class has only abstract (pure virtual) methods. We started out that way but now we allow the definition of common behavior even in the top-level method--making the top-level class, then, abstract but not an interface. I'll have to think about that. I don't think there are any downsides to adding this behavior, provided all the substates really do use that behavior.]

Link to comment

abstract class--What this means to us is: 1) we never instantiate an abstract class (just a restatement); 2) child classes override its methods (though it is not always necessary for every child to override every method), but the method definition in the abstract class may or may not be (in C++ terms) a pure virtual method--that is, it may have some common functionality that is called in the child implementations. This differs significantly from Dave's usage.

On reflection I think your interpretation is far better. Just because the parent object isn't instantiated doesn't mean it can't have useful code implemented in it's methods. (Though I do prefer 'abstract' over 'pure virtual.')

interface--Budd, p. 170, writes, "A class can have abstract (or pure virtual) methods and nonabstract methods. A class in which all methods were declared as abstract (or pure virtual) would correspond to the Java idea of an interface." This matches Dave's description of abstract class above; I prefer to reserve interface for this following Budd. (I guess this also means that all children must implement all the parent methods.)

The word "interface" is a bit tricky because it is ambiguous. Sometimes it is used to mean an Interface type, which is distinctly different from a class type; sometimes it is used to mean the public API exposed by a module, which may or may not include classes and methods. The class Budd describes has some similarities to Interfaces (namely that there is no implementation), but it still lacks the key features that make it an Interface type. Calling it an Interface implies it has certain capabilities that it, in fact, does not. It looks to me like it's a subset of abstract classes. (We could call it "fully abstracted," but I'm having a hard time convincing myself that we even need to bother with defining it.) Since Labview doesn't natively support Interfaces, I rarely use the (capitalized) term.

"interfaces" (with a lower case 'i' to mean a public api) is such a general and useful term in programming that I would be very reluctant to restrict its use to specific implementations (or lack thereof.)

[Hmm... I see that in Head First Design Patterns the top-level State or Strategy class are interfaces, which means that the top-level class has only abstract (pure virtual) methods. We started out that way but now we allow the definition of common behavior even in the top-level method--making the top-level class, then, abstract but not an interface. I'll have to think about that. I don't think there are any downsides to adding this behavior, provided all the substates really do use that behavior.]

I did the same in starting with fully abstract classes and eventually came to the same conclusion you did--there's no reason not to put common behavior in the parent class. And it's far easier to accept changing a fully abstracted class into just an abstract class than it is to change an Interface into an abstract class.

I don't have my copy of Head First handy, but in UML can't the stereotype <<interface>> mean either the type or an api?

Link to comment

The word "interface" is a bit tricky because it is ambiguous. Sometimes it is used to mean an Interface type, which is distinctly different from a class type; sometimes it is used to mean the public API exposed by a module, which may or may not include classes and methods. The class Budd describes has some similarities to Interfaces (namely that there is no implementation), but it still lacks the key features that make it an Interface type. Calling it an Interface implies it has certain capabilities that it, in fact, does not. It looks to me like it's a subset of abstract classes. (We could call it "fully abstracted," but I'm having a hard time convincing myself that we even need to bother with defining it.) Since Labview doesn't natively support Interfaces, I rarely use the (capitalized) term.

"interfaces" (with a lower case 'i' to mean a public api) is such a general and useful term in programming that I would be very reluctant to restrict its use to specific implementations (or lack thereof.)

I don't have my copy of Head First handy, but in UML can't the stereotype <<interface>> mean either the type or an api?

I agree in software development interface can have either meaning you mention. In UML, though, the meaning is really more specific; on the other hand, if we are generating code we can interpret this as we see fit.

For instance, if we are developing a UML model using the Java template, an Interface will support multiple inheritance (while a Java class will not). (In C++ any class can support multiple inheritance. In LabVIEW nothing can.) So in these instances a UML interface has a very precise meaning.

On the other hand, I create interfaces (either as abstract classes with I as the first character in the name or as true Interface types) to represent what I consider to be a software interface in LabVIEW. Moslty I just want to capture the signals and methods a given interface must implement so I can use these on an interaction diagram. In this case I choose to use this more in line with your second definition of interface, although both meanings are really pretty much the same when you think about it.

Link to comment

I thought about the last statement I just made. What I mean is that when I define a software interface (generally speaking, according to your second definition) I am describing attributes, signals, method signatures the software must implement. I am very definitely not defining how to implement the required behaviors. That really is what an Interface (e.g., Java meaning) is and why the methods are abstract (pure virtual).

So, if we apply this to the State Pattern or the Strategy Pattern, we realize that if we don't include behavior on the top-level class that we can always implement a new State or Strategy class beneath it without breaking existing behavior. (For instance, that behavior we thought always applied doesn't apply in some strange case). What we can do is add a superstate (as an abstract class, but not an interface) at the next level to capture all that common behavior. We ensure flexibility but add an extra class. In principle, at least, adding the extra class is a good idea. (The question is whether it hurts the application's performance, which in principle, at least, it definitely shouldn't.)

Interesting indeed!

Link to comment

I don't have my copy of Head First handy, but in UML can't the stereotype <<interface>> mean either the type or an api?

From uml (Interface):

As a classifier, an interface may be shown using a rectangle symbol with the keyword «interface» preceding the name.

So it is only the type, not the API.

Also, there is no stereotype <<interface>> in the standard profile.

I also was wrong with my saying about the Interface is different than a class, interface is a child of classifier, as is the class. There is also a class called InterfaceRealization, this is the one that has a very different inheritance tree (Dependency, Abstraction, Realization).

Felix

Edited by Black Pearl
Link to comment

Correction: I wrote above that a Java Interface supports multiple inheritance. I don't think that's correct. I think what I should have said is that an object (classifier) can implement more than one interface. I think that's correct. Maybe somebody can clarify this?

Anyway, UML 2.0 in a Nutshell, Dan Pilone, 2005, p, 30, has a pretty helpful explanation of interfaces. It says, in part:

"An interface is a classifier that has declarations of properties and methods but no implementations. You can use interfaces to group common elements between classifers and provide a contract a classifier that provides an implementation of the interface must obey.

...

Some modern languages, such as C++, don't support the concept of interfaces; UML interfaces are typically represented as pure abstract classes."

Head First Object-Oriented Analysis & Design, McLaughlin, Pollice, and West, 2006, has a good discussion on coding to an interface (how but also why).

Link to comment

As far as I can read/understand Java code, it supports multiple inheritance for interfaces. So you were correct.

Anyway, thanks for the citations you posted.

The note you posted above about uml is not complete (superstructure 7.3.24 ) :

* there is nothing that forces the methods to be abstract in the interface (it is mentioned for the properties!). -> I'm not clear with this.

* Constraints (Pre- and postconditions) are forced to be implemented with the interface.

* association can be forced by the interface.

* An interface can redifine Interfaces (I don't know what redefine means, sorry -> I want to be able to tell you next week).

* An interface can contain classifiers (thats really important, how to write a method which returns or accepts a MyCLassA as a parameter?)

* It is somehow (I don't understand yet) possible to say that a class requires a certain interface. I see the use: I want to call MyClass.MyOperation(iMyInterface).

As far as I see at the moment:

* Interfaces can only have abstract methods

* abstract class can have a mixture of abstract and implemented methods.

* if you have abstract methods only (as by interfaces or pure abstract classes), you can allow multiple-inheritance.

Also, turn it the other way:

* an abstract class can contain some code ([re]used in the child classes). An interface not.

* A very importantfeature is to call any object by it's interface.

Felix

Link to comment

Correction: I wrote above that a Java Interface supports multiple inheritance. I don't think that's correct. I think what I should have said is that an object (classifier) can implement more than one interface. I think that's correct. Maybe somebody can clarify this?

This is correct. There is no multiple inheritance in Java. Interfaces are a separate concept from inheritance. A class can implement multiple interfaces, but it can only inherit from one class. An interface is a set of function prototypes that the class must implement.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.