I'm trying to understand OOP SOLID principals and Design patterns. Here is a sample scenario Which I'm practicing with. Consider a media convertor app which accepts video, audio and photo files and each type has it's own different implementations of convert and different output extension. Properties like Id, FileName and Type is common but each type could have specific properties. for example Video file has video codec. I defined a base class which contains common properties. Here is my class:
public abstract class MediaFile {
public abstract string OutputExtension { get; }
public int Id { get; set; }
public string FileName { get; set; }
public MediaType Type { get; set; }
}
public enum MediaType { Video, Audio, Photo }`
But I don't know should I define an abstract method named convert inside this class and override it into subclasses or I should define a separate interface for handling convert process according separation of concerns principal. I have defined my models into a separate assembly (should I?) and if I put another interface put in charge of convert process, if convert process needs to be changed, there will be no changes and no recompile to domain models assembly. but if I simply add an abstract method, implementing the class would be easier and less code is needed. I have uploaded two approaches that I took. Please if you can check them and clarify What I'm doing wrong? I want to follow SOLID principals and also Abstract design pattern. Thanks link to download sample projects
some of the code is like this:
public abstract class MediaFile { public abstract string OutputExtension { get; } public int Id { get; set; } public string FileName { get; set; } public MediaType Type { get; set; } } public enum MediaType { Video, Audio, Photo } public class VideoMedia : MediaFile { private readonly string _outputExtension; public override string OutputExtension { get { return _outputExtension; } } // specefic fields for video media public string VideoCodec { get; set; } public string Duration { get; set; } public VideoMedia() { _outputExtension = "mp4"; this.Type = MediaType.Video; } } public class PhotoMedia : MediaFile { private readonly string _outputExtension; public override string OutputExtension { get { return _outputExtension; } } //specefic fields for photo media public int Height { get; set; } public int Width { get; set; } public PhotoMedia() { _outputExtension = "jpg"; this.Type = MediaType.Photo; } public string Resolution { get { return Width.ToString() + "x" + Height.ToString(); } } } //one approach is like this public interface IMediaConvertor { MediaFile Media { get; } void Convert(); } public class VideoConvertor : IMediaConvertor { private VideoMedia _media; public VideoConvertor(VideoMedia media) { _media = media; } public MediaFile Media { get { return _media; } } public void Convert() { Console.WriteLine("Converting a Video named {0} [VideoCodec={1}] to {2}", _media.FileName, _media.VideoCodec, _media.OutputExtension); } } public class PhotoConvertor : IMediaConvertor { private PhotoMedia _media; public PhotoConvertor(PhotoMedia media) { _media = media; } public void Convert() { Console.WriteLine("Converting a Photo named {0} [Resolution={1}] to {2}", _media.FileName, _media.Resolution, _media.OutputExtension); } public MediaFile Media { get { return _media; } } } public class MediaConvertorFactory { public IMediaConvertor GetConvertor(MediaFile media) { if (media.Type == MediaType.Video) return new VideoConvertor(media as VideoMedia); if (media.Type == MediaType.Audio) return new AudioConvertor(media as AudioMedia); return new PhotoConvertor(media as PhotoMedia); } } class Program { static void Main(string[] args) { var mediafiles = new List<MediaFile>(); mediafiles.Add(new AudioMedia() { FileName = "test-audio.wav", AudioBitrate = 64 }); mediafiles.Add(new VideoMedia() { FileName = "test-video.avi", VideoCodec = "H.264" }); mediafiles.Add(new PhotoMedia() { FileName = "test-photo.bmp", Width = 1024, Height = 764 }); mediafiles.Add(new VideoMedia() { FileName = "test-video2.mkv", VideoCodec = "Xvid" }); foreach (var media in mediafiles) { MediaConvertorFactory factory = new MediaConvertorFactory(); factory.GetConvertor(media).Convert(); } Console.ReadKey(); } } //another approach is to add abstract method to base class and overide it which you can see in my project files