Object oriented design Idea (C #)

Source: Internet
Author: User
Tags abstract implement inheritance interface key return tostring

with wings to fly, lack of flexible code is like a bird with a broken wing. Can not fly, there is less of the spirit of the smart. We need to bring the code to the warm sun, let turn cold wings to fly again. With examples, by applying OOP, design patterns, and refactoring, you can see how the code is resurrected in a step-by-step way. in order to better understand the design idea, the example is as simple as possible. But as demand increases, the process becomes more complex. At this point there is the need to modify the design, refactoring and design patterns can be useful. Finally, when the design becomes perfect, you will find that even if the demand is increasing, you can be refreshed and free of trouble with the code design.

Suppose we want to design a media player. The media Player currently supports only audio files MP3 and WAV. If you don't talk about design, the player you design may be simple:

public class MediaPlayer
{
private void PlayMp3 ()
{
MessageBox.Show ("Play the mp3 file.");
}

private void Playwav ()
{
MessageBox.Show ("Play the WAV file.");
}

   public void Play (string audiotype)
   {      
      switch (audiotype.tolower ())
      {
          case ("MP3"):
              PlayMp3 ();
             break;
          case ("wav"):
              playwav ();
             break;             
     }      
  }
}

Naturally, you will find this design very bad. Because it does not provide a minimum scale for future changes in requirements. If your design turns out to be the case, then when you're overwhelmed by the overwhelming demand change, you might want to get the design where it should be, the Recycle Bin for the desktop. Carefully analyze this code, it is actually one of the oldest structure-oriented design. If you want to play more than just MP3 and WAV, you will constantly add the appropriate playback method, and then let the switch clause grow longer until you reach the point where you can't see it.

Well, let's first experience the spirit of the object. According to OOP, we should think of MP3 and WAV as a separate object. So is that so?

public class MP3
{
public void Play ()
{
MessageBox.Show ("Play the mp3 file.");
}
}

Good, you already know how to set up an object. Even more gratifying is that you unknowingly applied the refactoring method, the original garbage design method name changed to the Unified Play () method. You are in the design behind, you will find such a renaming is how key! But it seems you don't have the hit to change the MediaPlayer code in the current way, and there's not much change in substance.
since both MP3 and WAV belong to audio files, they all have audio files in common, why not create a common parent class for them?

public class Audiomedia
{
public void Play ()
{
MessageBox.Show ("Play the Audiomedia file.");
}
}

Now we have introduced the idea of inheritance, and OOP is a kind of image. Proud of the rest, or seriously analyze the real world. In fact, in real life, we play only a specific type of audio files, so this audiomedia class does not actually use the situation. The corresponding design is that the class will never be instantiated. So, you have to move the surgery and change it to an abstract class. Okay, now the code has a bit of a sense of oop:

Look at the current design, that is, to meet the hierarchical relationship between classes, but also to ensure that the class of the principle of minimization, more conducive to expansion (here, you will find play method name to change more necessary). Even if you now add to the WMA file playback, only need to design WMA class, and inherit Audiomedia, rewrite play method is OK,
The play method of the MediaPlayer class object does not have to change at all.

is this the end of the painting? Then the tricky customer is never satisfied, they are complaining about the media player. Because they do not want to watch the football game, only to hear the moderator's commentary, they are more eager to see the football star running on the stadium. In other words, they want your media player to be able to support video files. You should be miserable again, because the original software design seems to be a problem when you change the hardware design. Because video files and audio files have a lot of different places, you can not be lazy, let the video file object to recognize the audio file as a father Ah. You need to design a different class object for the video file, assuming we support the RM and MPEG video formats:

Public abstract class Videomedia
{
public abstract void Play ();
}

public class Rm:videomedia
{
public override void Play ()
{
MessageBox.Show ("Play the RM file.");
}
}

public class Mpeg:videomedia
{
public override void Play ()
{
MessageBox.Show ("Play the MPEG file.");
}
}

The bad thing is, you can't enjoy the original MediaPlayer once and for all. Because the RM file you want to play is not a audiomedia subclass.

but don't worry, because the interface of this tool you have not used (although you can also use abstract class, but in C # only support the single inheritance of classes). Although video and audio formats are different, don't forget that they are all a kind of media, many times they have many similar functions, such as playback. Depending on the definition of the interface, you can completely implement the same interface for a series of objects of the same function:

public interface Imedia
{
void Play ();
}

Public abstract class Audiomedia:imedia
{
public abstract void Play ();
}

Public abstract class Videomedia:imedia
{
public abstract void Play ();
}

Change the design of the MediaPlayer again OK:

public class MediaPlayer
{
public void Play (Imedia media)
{
Media. Play ();
}
}

now, to sum up, from the evolution of the MediaPlayer class, we can draw the conclusion that when we invoke the properties and methods of the class object, we try to avoid the concrete class object as the passing parameter, but should pass its abstract object, better be the transfer interface, and completely peel off the actual call and the concrete object. This can improve the flexibility of your code.

However, the matter is not finished. Although everything seems perfect, we ignore the fact that we forget the MediaPlayer caller. Do you remember the first switch statement in the article? It looks like we've got rid of this problem very nicely. In fact, I played a trick here to postpone the switch statement. Although the code looks neat in the MediaPlayer, the annoyance is simply passed on to the MediaPlayer caller.
For example, in the main program interface:

public void Btnplay_click (Object Sender,eventargs e)
{
Switch (cbbMediaType.SelectItem.ToString (). ToLower ())
{
Imedia Media;
Case ("MP3"):
Media = new MP3 ();
Break
Case ("WAV"):
Media = new WAV ();
Break
other types slightly;
}
MediaPlayer player = new MediaPlayer ();
Player. Play (media);
}
The user decides which file to play by selecting the option for the Cbbmediatype combo box, and then clicks the plays button to execute.

The

       is now in the design mode, which creates different types of patterns based on different situations, and the factory model is best. What products do we need to produce in our factory first? Although there are two different types of media audiomedia and Videomedia (which may be more later), they both implement the Imedia interface,
so we can see it as a product, using the factory method model. First is the factory interface:

public interface imediafactory
{
   Imedia Createmedia ();
}

       then build a factory for each media file object and implement the factory interface uniformly:

public class mp3mediafactory:imediafactory
{
   public imedia Createmedia ()
   {
       return new MP3 ();
  }
}
public class Rmmediafactory:imediafactory
{
   public imedia Createmedia ()
   {
       return new RM ();
  }
}
//other factory slightly;

writing here, some people may ask, why not directly to Audiomedia and videomedia to build factories? Simple, because there are different types of derivations in Audiomedia and Videomedia, and if you build a factory for them, you still use the switch statement in the Createmedia () method. And since all two classes implement the Imedia interface, which can be considered a type, why bother to move abstract Factory mode to produce two kinds of products? You may also be asked, even if you use this method, do you want to use a switch statement when deciding which factory to create specifically? I admit that this view is right. However, the immediate benefit of using Factory mode is not to solve the problem of switch statements, but to delay the generation of objects to ensure the flexibility of the code. Of course, I've got one last trick that doesn't make it out, and in the back you'll find that the switch statement actually disappears completely.

Another question is, is it really necessary to implement the Audiomedia and Videomedia two abstract classes? Isn't it simpler to have subclasses implement interfaces directly? For the requirements mentioned in this article, I think you are right, but do not rule out audiomedia and videomedia they will be different. For example, the audio file only needs to provide the interface to the sound card, and the video file also needs to provide the interface to the video card. If you let MP3, WAV, RM, MPEG directly implement the Imedia interface, and not through Audiomedia and Videomedia, in the design of other requirements is not reasonable. Of course, this is not included in the scope of this article.

public void Btnplay_click (Object Sender,eventargs e)
{
Imediafactory factory = null;
    switch (cbbMediaType.SelectItem.ToString (). ToLower ())
    {
        case ("MP3"):
              factory = new Mp3mediafactory ();
             break;
        case ("wav"):
              factory = new Wavmediafactory ();
             break;  
        //other type slightly;
   }
    MediaPlayer player = new MediaPlayer ();
    player. Play (factory. Createmedia ());
}

Writing here, we go back to look at the MediaPlayer class. In this class, the play method is implemented and the play method of the corresponding media file is invoked according to the parameters passed. In the absence of a factory object, it seems that the class object works very well. In the case of a class library or Component Designer, he provides such an interface for the Master interface programmer to invoke. However, after the introduction of the factory model, it is superfluous to use the MediaPlayer class inside. So what we want to keep in mind is that refactoring doesn't just add new content to the original code. When we find some unnecessary design, we also need to decisively delete these redundant code.
public void Btnplay_click (Object Sender,eventargs e)
{
Imediafactory factory = null;
Switch (cbbMediaType.SelectItem.ToString (). ToLower ())
{
Case ("MP3"):
Factory = new Mp3mediafactory ();
Break
Case ("WAV"):
Factory = new Wavmediafactory ();
Break
other types slightly;
}
Imedia Media = Factory. Createmedia ();
Media. Play ();
}

If you don't realize the benefits of the Imedia interface at the beginning, you should have understood it here. We used the interface in the factory, and in the main program, we still use that interface. What are the benefits of using an interface? That is, your main program can be compiled without a specific business class. Therefore, even if you add new business, your main program is not to change.

Now, however, it seems that the ideal of not changing the main program is still unfinished. Did you see it? In Btnplay_click (), some instances of concrete classes are still created with new. If no complete and specific classes are separated, once the specific class of business is changed, for example, add a new factory class, still need to change the main program, not to mention the annoying switch statement still exists, it seems to be the breeding of cancer on the wings, suggesting that, although the wings have been raised from the turn cold world, but this pair of wings is still sick, and cannot fly normally.

It's time to use a configuration file. We can place the corresponding information for each type of media file in the configuration file, and then choose to create a specific object based on the configuration file.
Also, this method of creating objects will be done using reflection. First, create the configuration file:

<appSettings>
<add key= "MP3" value= "Wingproject.mp3factory"/>
<add key= "wav" value= "Wingproject.wavfactory"/>
<add key= "rm" value= "Wingproject.rmfactory"/>
<add key= "MPEG" value= "Wingproject.mpegfactory"/>
</appSettings>

Then, in the Form_Load event of the main program interface, read all the key values of the configuration file and populate the Cbbmediatype combo box control:
public void Form_Load (object sender, EventArgs e)
{
CbbMediaType.Items.Clear ();
foreach (string key in ConfigurationSettings.AppSettings.AllKeys)
{
CBBMEDIATYPE.ITEM.ADD (key);
}
Cbbmediatype.selectedindex = 0;
}

Finally, change the main program's Play button click event:
public void Btnplay_click (Object Sender,eventargs e)
{
String mediatype = CbbMediaType.SelectItem.ToString (). ToLower ();
String factorydllname = Configurationsettings.appsettings[mediatype]. ToString ();
Medialibray is a reference to the media file and the factory assembly;
Imediafactory factory = (imediafactory) activator.createinstance ("Medialibrary", Factorydllname). Unwrap ();
Imedia Media = Factory. Createmedia ();
Media. Play ();
}

Now the wings of birds are not only resurrected, they have the ability to fly, but we also give these wings a stronger function, it can fly higher, fly farther!

Enjoy the freedom to fly. Imagine if we want to increase the playback function of some kind of media file, such as AVI file. So, we just need to create the AVI class in the original business assembly and implement the Imedia interface while inheriting the Videomedia class. In addition, create the Avimediafactory class in the factory business and implement the Imediafactory interface. If the new factory type is wingproject.avifactory, add the following line to the configuration file:
<add key= "AVI" value= "Wingproject.avifactory"/>.
And what about the main program? There is no need to make any changes, even without recompiling, this pair of wings can still fly freely!

Public abstract class Audiomedia
{
public abstract void Play ();
}

public class Mp3:audiomedia
{
public override void Play ()
{
MessageBox.Show ("Play the mp3 file.");
}
}

public class Wav:audiomedia
{
public override void Play ()
{
MessageBox.Show ("Play the WAV file.");
}
}

public class MediaPlayer
{
public void Play (Audiomedia media)
{
Media. Play ();
}
}

public class WAV
{
public void Play ()
{
MessageBox.Show ("Play the WAV file.");
}
}



Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.