Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Polymorphism design question

First of all sorry for the long question, but I couldn't write it any shorter :)

Real world example: we have large roll of paper, which contains small 'stickers' printed on them. Each sticker has a code. First two letters of the code tells us what kind of a sticker this is (sticker that represents new roll, sticker that represents end of current roll, sticker which should go to quality control,... but most of them are normal enumerated stickers).

For example sticker with the code XX0001 means, that after it there should be only normal enumerated codes (like NN0001 to NN9999), always the same number. Code QC0001 tells us, that next 10 codes (from QC0001 to QC0010) should go to quality control.

I designed the application so, that each type of a sticker is its own class - NormalSticker, BadSticker, ControllSticker, QualitySticker,... They all inherit from a SticerBase class, which contains some common data for all of them (quality of the scan, date and time of the scan, content of the code). Instances of these classes are created in a static Parser class, which checkes the code and returns appropriate object back to us.

This all works OK, but now I got to a halt. I have also a Roll class, which has a set of Stickers, implemented as List<StickerBase>. This class has a public AddSticker(StickerBase) method, with which we add stickers to the roll. But this method should contain some logic, for example if we get the code XX001, then next 9999 stickers should be from NN0001 to NN9999. Only option I see here, is to make desicions based on the type of the sticker, like:

public void AddSticker(StickerBase sticker)
{
    if (sticker.GetType().Equals(typeof(StickerNewRoll)))
    {
        // Next 9999 sticker should be in the form of NN0001 to NN9999
    }

    if (sticker.GetType().Equals(typeof(EnumeratedSticker)))
    {
        // Add 9999 stickers to the list, other business logic...
    }

    if (sticker.GetType().Equals(typeof(QualitySticker)))
    {
        // Stop the machine and notify the worker
    }
}

I would be really surprised if this is the right approach. Any ideas?

Edit - possible solution: because for each sticker I know how the next one should look like, I can add new method public Sticker NextStickerShouldLookLike() method to each Sticker class. In the validation logic (similar to Péter Török's answer) I can just check if current sticker is the same as previousSticker.NextStickerShouldLookLike(). The Validate method would have two input parameters - current and previous sticker.

like image 569
sventevit Avatar asked Feb 03 '11 11:02

sventevit


1 Answers

Do you want to add the set of stickers associated with a specific sticker in a single move, or do you want to validate that stickers added conform to the constraints set by the latest special sticker?

In the first case you could add a polymorphic GetAssociatedStickers() method to your sticker classes, which returns the set of stickers from NN0001 to NN9999 to a sticker with code XX001, etc. Then you can add that set of stickers right after the control sticker.

Update

For validation, you could have a new interface StickerValidator, and a method GetValidator in your sticker classes. Special stickers would return a proper validator object (which could be implemented as an anonymous class or an inner class), while regular stickers would return null. Then AddSticker can be modified to look something like

public void AddSticker(StickerBase sticker)
{
    if (sticker.GetValidator() != null)
    {
        this.validator = sticker.GetValidator();
        // add the sticker to the list
    }
    else
    {
        if (this.validator == null || this.validator.validate(sticker))
        {
            // add the sticker to the list
        }
        else
        {
            // set error state
        }
    }
}
like image 135
Péter Török Avatar answered Nov 16 '22 03:11

Péter Török