1

I am doing a small application for a neighbour and quite confused about the design at the moment. It looked pretty simple to start with, yet now I am stuck. I understand the inheritance and thus,

  • All gifts must be wrapped.
  • Gift is an abstract class.
  • Wrapping Style is an abstract class.
  • Birthday gift inherits from Gift.
  • Origami Style inherits from Wrapping Style.

Scenario: User gives a gift to the shop with its identity (e.g. bday for family, bday for colleague). So there's a birthday gift that is for a colleague, which is different from a gift for a family. User specifies which wrapping style they like to use. (e.g. Origami, Western) In this case, let's say birthday gift for colleague must be wrapped using a birthday style under Origami.

But how can I connect gift with wrapping? At first wrapping looks like an interface to me. So a gift implements it. But the fact that wrapping each main wrapping styles has sub wrapping styles makes it complicated. How can the gift object birthday for colleague knows which interface to implement? It seems like birthday, wedding supposed to be abstract classes too, since only 3rd generation of gift class is a concrete class.

How can I get this design to make sense yet easy to code now and have room for modifications/improvements later?

enter image description here

aspiring
  • 1,557
  • 2
  • 20
  • 43
  • I think you need to more clearly specify what the domain is and what problem your program is trying to solve before designing a complex class hierarchy. What concepts are you trying to model? From the limited description, it sounds like you are trying to put too many concepts into the class hierarchy. For example, is a *friend's wedding gift* a kind of *gift*? Or does a *gift* have an *occasion* (e.g. wedding, birthday, etc.), a *relation* (e.g. family, friend, colleague), and a *wrapping style*. Note how those nouns can be their own types. Map out all the concepts and their relations first. – Mike Zboray Nov 01 '14 at 03:58
  • @mike z Gift has different *types* of gifts. Each of these child gifts have *sub types*. Birthday gift can never be same as Graduation gift. But as square and circle inherit from shape class, my gifts inherit from gifts class. One of the confusions I have, should I write 12 different types of concrete classes (bday family, bday colleague, wedding friend, wedding family, graduation friend, graduation family etc) inheriting from gift abstract class because each of them have few their own unique properties and methods? That makes really no sense at all :( – aspiring Nov 01 '14 at 04:42
  • 1
    If a birtday gift can never be the same as a graduation gift, why inherit from the same base class at all? The proliferation of subtypes in your model is why I proposed instead of making a gift subtype for each occasion/relation pairing, making them properties of the gift object. The applicability of that idea depends on what this program is designed to do. As some people have already proposed, a gift is not a kind of wrapping style, it has a wrapping style. – Mike Zboray Nov 01 '14 at 05:11

3 Answers3

1

In order to associate each gift with wrapping, you do not want to implement wrapping. That will not work. Instead, include the wrapping as a variable in Gift.

You seem to have method would be to use abstract classes (which are essentially partial implementations):

public abstract class Gift
{
    public IWrappingStyle wrapping { get; private set; }

    public Gift(IWrappingStyle wrapping)
    {
        this.wrapping = wrapping;
    }

    public void Unwrap()
    {
        // code common to all gifts for unwrapping
        // ...
    }
}

public interface IWrappingStyle
{

}

Then you could continue representing the second level of types as interfaces for Wrapping Style and abstract classes for gifts, and classes as the lowest level for rest of your needed types. Adding a new one would be as simple as adding a new class.

Then to use, you could do:

Gift g = new GraduationSchoolGift(new OrigamiBirthdayWrapping());

Don't forget to use folders!

Folders to stay organized.


However, unless you have some specific different behaviors for different wrapping and such, I would argue that you could use a much simpler layout:

public class Gift
{
    public String GiftType { get; private set; }
    public String WrappingStyle { get; private set; }

    public Gift(String giftType, String wrappingStyle)
    {
        this.GiftType = giftType;
        this.WrappingStyle = wrappingStyle;
    }
}

Then, if you (again) organize your files in folders like so:

Organized

Here are the respective files (the namespace is important):

Gift types:

namespace GiftWrapping.GiftTypes
{
    public class Birthday
    {
        public static const String FIFTH_BIRTHDAY = "Birthday Fifth";
        public static const String TENTH_BIRTHDAY = "Birthday Tenth";
    }
}

namespace GiftWrapping.GiftTypes
{
    public class Wedding
    {
        public static const String FAMILY = "Wedding Family";
        public static const String FRIENDS = "Wedding Friends";
    }
}

Wrapping Styles:

namespace GiftWrapping.WrappingStyles
{
    public class Origami
    {
        public static const String BIRTHDAY = "Origami Birthday";
        public static const String WEDDING = "Origami Wedding";
    }
}

namespace GiftWrapping.WrappingStyles
{
    public class Western
    {
        public static const String SCHOOL = "Western School";
        public static const String WEDDING = "Western Wedding";
        public static const String UNIVERSITY = "Western University";
    }
}

Now usage becomes:

Gift g = new Gift(GiftTypes.Wedding.FAMILY,
                  WrappingStyles.Origami.BIRTHDAY);
Entity
  • 7,972
  • 21
  • 79
  • 122
0

Actually write an interface is a good practice. They can really help you when you writing a unit test and is basis for SOLID. So you can try somthing like:

  public interface IGift
    {
        public void Wrap(IWrappingStyle wrappingStyle)
        {

        }
    }

    public interface IWrappingStyle
    {

    }

With such kind of object dependency you can use somthing like Strategy pattern to procces wrapping style based on type of the class.

Andrei
  • 1
  • 1
-1

Gift and wrapping are separate entities, use dependance injection.

Class wrapping{
    protected $gift;

    public __construct( $gift ){
        $this->gift = $gift
    }

    public getGift(){
       return $this->gift;
    }

}

Class gift{


}


$g = new gift()

$w = new wrapper($g);

This way you don't need to change wrapping for each new gift, or gift for each new wrapping. Whether you Interface gift,or make it abstract depends on the functionality. Same goes for wrapping. Don't mix them at the "code" level even your diagram above shows they are separate objects.

Personally I would either interface gift, or make an base abstract class for it. Then you can rely on future gifts having the code you need inside of wrapping.

Ha just realized this was C, how did I do that. Anyway the idea is the same even if it's not PHP.

Cheers.

ArtisticPhoenix
  • 21,464
  • 2
  • 24
  • 38
  • Gift being an abstract class is obvious. But I don't understand how it can be connected with wrapping due to the levels of gift types. What do you mean by "Whether you Interface gift,or make it abstract depends on the functionality"? – aspiring Nov 01 '14 at 03:39
  • If all gifts share common code, the base is abstract. Otherwise you will have to recode that common functionality in all future gifts. If gifts could have widely different code, but you just need to rely on the method names etc. then it is an interface. – ArtisticPhoenix Nov 01 '14 at 03:41
  • Ofcourse the abstractness is written in my question "gift class is abstract", "giftwrapper is abstract"! But I am at a loss to implement what you had suggested. Can you explain on the design with an extended example or lead me to an example? My main question is how does a gift decide which style to adapt? – aspiring Nov 01 '14 at 03:42
  • I wouldn't create a giftwrapper. That was my point. Don't mix the code of the two. One contains the other. They are not the same thing. A car is not a garage, you don't make a cargarage class. You put the car in the garage, so to speak. For example what if you want to wrap 2 gifts in the same wrapper. It would be impossible if you mix their code. – ArtisticPhoenix Nov 01 '14 at 03:43
  • I am reading this thread now: [Why does one use Dependency Injection](http://stackoverflow.com/questions/14301389/why-does-one-use-dependency-injection). Overall, I still feel that I have to create x number of concrete classes? and y number of style classes? And can you please clarify clearly there're no interfaces involved? I am at basic level programming. – aspiring Nov 01 '14 at 03:48
  • Exactly, the point is though. They are not the same object, if one is an interface and the other is abstract. That is a separate question. – ArtisticPhoenix Nov 01 '14 at 03:52
  • 1
    @ArtisiticPhoenix I'm not sure what language you're using but that doesn't look like C#. – Entity Nov 01 '14 at 04:02
  • @ArtisiticPhoenix I really don't get your intention. Because I asked few questions to clarify your answer, but I don't seem to understand your comments. And I didn't downvote you though. – aspiring Nov 01 '14 at 04:45
  • @aspiring - sorry my webserver just came back online raid failed today. Anyway, I don't know how I can explain it better to create two object trees for this, one for gifts, one for wrappers. And, to not mix that functionality. – ArtisticPhoenix Nov 01 '14 at 06:02