I know you can't overload a method in Smalltalk according to the parameter's class. I am left with this design problem:
I have three classes: one that implements a Mail, one that implements a Sentence and one that implements a Word. These three classes have a method called addContent that receives as an argument a String. Mail and Sentence have another method called addContent that receives a Word, and Mail has another addContent that receives a Sentence. On the side, all of them have a method called returnAsString that return the content as a string.
I am left to the following possibilities:
Implement them through dependencies: Mail has a collection of Sentence and Sentence has a collection of Word (and Word just has a string). Then that addContent could be implemented by asking the parameter to return its contents in a string, and make the object's attribute use the addContent(String) to load it. The problem I find with this approach is that I'd have to add a method for a String object to return itself as a String, and for the rest that method should be returnAsString
Make them all inherit form a base abstract class. I just don't know how this would work, because I'd also make Word have a method to addContent through a Sentence, and that is wrong.
Any ideas?
Thanks
Your friend is Double Dispatch.
You will have to add a specialized addContent: method on each of the classes Mail, Sentence and Word. I give you the example for the combination Mail and String.
Mail >> addContent: content
content addToMail: self
String >> addToMail: mail
mail addStringContent: self
Mail >> addStringContent: aString
"here you have the explicit type encoded in the selector"
self todo: 'Add a string to the mail"
Similarly you can fix the combinations for adding Strings to Sentences, Words to Sentences, and Sentences to Mails.
Related
I would like to know if there is a design pattern to cover making multiple objects representing mutiple permutations of a string. For example:
I have a database table containing item names.
Each item has a sort of "signature" (can't think of a better word for it), which is all the letters of the item name, sorted in alphabetical order with the spaces removed.
Given a "soup string" of jumbled up letters, I would like to sort those letters in alphabetical order to match it to a signature in the database, but here's the catch...
Each soup string may contain a few extra letters. So what I'm looking for is a design pattern which would be suitable for taking a string and returning a list of objects, each representing a permutation of that soup string, which I can then fire at the database.
I was thinking about just using a factory, but isn't this outside of the scope of a factory? It does contain logic, (am I right in saying this is not business logic?), but perhaps this is acceptable for a factory or factory method? Then again, perhaps this is an perfect usecase for a factory.
Ultimately, I will probably just go with the factory method. I just wanted to see if there was a better option.
Thanks in advance.
Let's start with an object-oriented way of creating n objects from a given item. First, let's assume that the item is of type String; you can create a class Permutations which implements the interface Iterable<String> (basically, an object that acts as a list of elements of type String)
data class Permutations(val strings: Iterable<String>): Iterable<String> {
constructor(string: String): this(...) {
# transform string to permutations here (bonus: with lazy computations)
}
override fun iterator(): Iterator<String> = strings.iterator()
}
Now, any object of type Permutations can replace a list of type String. Note that this class has two constructors, one takes a list of strings (the primary basic constructor) and one takes just one string and transforms it. This is not a design pattern; it's just a nice way to write objects out of objects without using static methods on util classes.
You can encapsulate the computation that transforms your string into permutations in (1) a different object (such as a strategy class), (2) a lambda function or (3) write our logic into the constructor (not recommended). The way you encapsulate the computation depends on how much flexibility you need. :)
Edit: Small improvement for the primary constructor.
I use pin_ptr for cli::array types and everything works fine.
Is it possible to do the same with System::Collection::Generic::List which I believe is a contiguous block of memory?
The obvious
List<double>^ stuff = gcnew List<double>( 10 );
cli::pin_ptr<double> resultPtr = &stuff[ 0 ];
gives a compiler error "error C2102: '&' requires l-value" presumably because the indexed property returns something that is not a l-value! So is there another way to do this. I have played around with interior_ptr as well but have not found anything that works yet.
I know that I could call ToArray on the List but the whole point is to not copy stuff around.
No, this is not possible.
True, a List does use an array behind the scenes, but the [] operator is different. With an array, [] is simple pointer math, but with a List, [] is a full-fledged method call. That's why the & isn't working: you can take the address of an array location, but you can't take the address of a value returned from a method.
Think about it like this: If they wanted to, they could change the implementation of List without changing its external interface. It would be possible to change List to store the list contents in memory gzip-compressed. In that case, stuff[0] is generated on-the-fly by the [] method which does the decompression, so there is no single memory location that contains stuff[0] to pin.
Edit
Yes, internal to the List class, the contents are contiguous in memory. You can see this in the source that Microsoft has provided. However, the List class does not make that array public: The public interface to the List class is the public methods & properties, only. The public methods & properties present a contract, and the array that the values are stored in are not part of that contract. Microsoft would never do this, but they could do a gzip-compressed implementation of List, and the public contract of the List class wouldn't change. You should only write your code to the public methods & properties of a class, not to the internals that may change at any time.
I wonder if it's possible to find method of object which returns specific type?
For example I want to look in autocompletion all methods which return String:
For this example it's easy to find it just by scrolling down, but for objects with large number of methods it can be painful.
Actually there is no default sorting by return type(yet?), even in class structure view.
I'm using smart completion(ctrl+shift+space) for this purposes in place where only certain type is accepted, for example:
String s = aClass.<smart completion here>
It will show methods from a aClass that return String at the beginning.
In the header information of an ABAP Objects class, I can enter a message class to use with the MESSAGE statement. This works like the MESSAGE-ID statement of a report or a function pool. Since I can't find the message class I entered in the header data anywhere in the generated sections, I assume that it's generated into the top-level CLASS-POOL statement somewhere.
For some libraries (for examples, the BAL application logging), it's necessary to specify the message class using a variable or a method parameter. Up to now, I've defined a constant that specified the message class and used that constant. I'm wondering if it's possible to access the message class specified in the header data in some other way so that I can get rid of that redundant variable.
Has anyone found a way to do so?
EDIT: The new way should be easier than the old one - I'm not crazy enough to add a CLASS-CONSTRUCTOR and perform some database access or SEO_* function calls just to get rid of that constant.
I think you need a CLASS-CONSTRUCTOR to set a class attribute with the message class.
The MESSAGE statement with INTO clause has the side effect of setting the SY- system variables. So you could put into your CLASS-CONSTRUCTOR something like:
DATA: lf_dummy TYPE string.
MESSAGE s999 INTO lf_dummy.
af_msgid = sy-msgid.
You could use the class builder API:
data the_class type ref to cl_oo_class.
create object the_class
exporting
clsname = `ZCL_SOMECLASS`.
data message_class type arbgb.
message_class = the_class->class-msg_id.
I haven't come across any syntax to do what you ask. For the reasons I outline below, I could believe that SAP never saw a need to include such functionality.
In my experience, the message class is an attribute of the message, not of the object that raises it, so it should be kept together with the type, number, and variables of the message. For example if my object is returning the number of an error, it should be returning the id (class) as well.
In this light I cannot see a reason why you would ever need to know the message-class assigned to an ABAP-OO class, you would only ever need to know the message-class of the messages returned by the ABAP-OO class.
The way I usually manage this is to raise my messages into a dummy field, and then use a subroutine to populate the contents of the sy-msg* fields into a BAPIRETURN structure. Then I return this BAPIRETURN structure to the caller. This way the type, id, number, and variables of the message are all kept together.
I have a group of classes (say for validation rules). Each one returns a true or false.
I use id and call a method signature for each one of the classes and get the results allowing me to dynamically create validation rules.
Worked great until...
I have a new class that takes an extra parameter to come up with its validation.
What is the best way to deal with this?
Modify every other classes method signature to take a parameter that they don't need?
Probably the most appropriate course of action is to abstract your parameter passing into an object that can have a variable profile of variables.
Of course, more simply, Objective-C does allow for a variable parameter list much like C:
void method(int a, ...) // in C
- (void) method:(id) firstObject, ... // in ObjC
Apple has Technical Q&A on the very subject.