برای reuse کردن کدهای نوشته شده، دو تکنیک رایج Inheritance و Composition وجود دارد.
برای تکنیک inheritance کدهای زیر را در نظر بگیرید.
public class XmlSerializer { public virtual string Serialize(Object target) { return "" } }
یک serialize نوشته شده است که یک object را دریافت می کند و آن را به xml تبدیل می کند.
این کلاس توسط کلاس EncodedXmlSerializer از طریق ارث بری reuse و extend شده است.
public class EncodedXmlSerializer : XmlSerializer { public override string Serialize(object target) { //.... return base.Serialize(target); //.... } }
و در نهایت کلاس EncodedXmlSerializer توسط کلاس CompressingEncodedXmlSerializer ارث بری شده است و به مجموعه رفتارهای آن، یک رفتار جدید اضافه شده است.
public class CompressingEncodedXmlSerializer : EncodedXmlSerializer { public override string Serialize(object target) { //.... return base.Serialize(target); //.... } }
برای تکنیک composition کدهای زیر را در نظر بگیرید.
یک interface به نام IXmlSerializer تعریف شده است که یک object دریافت می کند و قرار است یک serialization انجام دهد.
public interface IXmlSerializer { public string Serialize(object target); }
یک کلاس XmlSerializer داریم که عملیات serialize to xml را انجام می دهد.
public class XmlSerializer : IXmlSerializer { public string Serialize(object target) { return "" } }
کلاس های EncodingXmlSerializer و CompressingXmlSerializer داریم که IXmlSerializer را پیاده سازی کرده اند و یک instance از IXmlSerializer در constructor دریافت می کنند و از طریق متد Serialize، رفتاری را به آن اضافه می کنند.
public class EncodingXmlSerializer : IXmlSerializer { private readonly IXmlSerializer _serializer; public EncodingXmlSerializer(IXmlSerializer serializer) { _serializer = serializer; } public string Serialize(object target) { //.... return _serializer.Serialize(target); //.... } }
public class CompressingXmlSerializer : IXmlSerializer { private readonly IXmlSerializer _serializer; public CompressingXmlSerializer(IXmlSerializer serializer) { _serializer = serializer; } public string Serialize(object target) { //.... return _serializer.Serialize(target); //.... } }
زمانی که از ارث بری استفاده می کنیم، ممکن است متدهایی را ببینم که متدهای داخلی کلاس super type ما هستند. به خاطر این از اصطلاح white box برای آن استفاده می شود. اما در composition، فقط به api بیرونی abstract دسترسی داریم و از اصلاح black box برای آن استفاده می شود.
اما بزرگترین تفاوتی که احساس می شود، موضوع compile time بودن inheritance و run time بودن composition است. در compile time ترتیب استفاده از کلاس ها مشخص می شود و اگر بخواهیم مکانیزم را تغییر دهیم باید در سطح compile این تغییرات را ایجاد کنیم و ممکن است هزینه بالایی داشته باشد. در حالی که اگر یک ساختار composite داشته باشیم در run time تصمیم می گیریم که به چه صورت ساخته شود و می توانیم هر ترکیبی از آن را داشته باشیم.
var serializer = new CompressingXmlSerializer (new EncodingXmlSerializer(new XmlSerializer()));
در طراحی هایی که براساس composition پیاده سازی می شوند، reuse کردن objectها در راستای رسیدن به functionalityهای مختلف مانند بازی لگو با چسباندن اجزای مختلف در کنار هم، ساختارهای جدیدی را ایجاد می کند.
عمده design patternها، بر composition تاکید دارند.