الگوی کارخانه انتزاعی

الگوی کارخانه انتزاعی، در الگوهای نرم‌افزاری روشی برای جمع‌بندی گروهی از کارخانه‌های مجازی است که ساختار مشابهی دارند ولی از کلاس‌های مختلفی تشکیل شده‌اند .[۱]

در حالت عادی، برنامه زیرشاخه یک ساختار یکپارچه از کارخانه انتزاعی را می‌سازد و سپس از واسط کاربری می‌خواهد که شیءهای مختلفی در آن تم (دارای شباهت در تعدادی از ویژگی‎ها) بسازد. برنامه زیر شاخه نمی‌داند (یا اهمیت نمی‌دهد) که چه شیءای را از کتابخانه گرفته است. چون تنها از شی ساخته شده استفاده می‌کند. [۱] این الگو جزئیات اجرا و استفاده از گروهی از اشیاء را، از نحوه پیاده‌سازی آنها جدا می‌کند. چرا که ساخت اشیاء در کارخانه صورت می‌گیرد.[۲]

به طور مثال کلاس کتابخانه انتزاعی DocumentCreator که رابطی برای ساخت تعدادی از کتابخانه‌ها (ازجمله createLetter و createResume) را فراهم می‌کند. این سامانه می‌تواند به هر تعداد از نسخه‌های کتابخانه‌های مشتق شده از کلاس DocumentCreator را داشته باشد. مثل FancyDocumentCreator یا ModernDocumentCreator هر کدام با یک پیاده‌سازی متفاوت از createLetter و createResume شی‌های مربوط را تولید کنند. و هر کدام از یک کلاس انتزاعی ثابتی مانند Letter یا Resume ساخته می‌شوند. برنامه زیرشاخه یک ساخته از DocumentCreator را دریافت می‌کند که به آن کارخانه انتزاعی گفته می‌شود. اشیاء ساخته شده همگی توسط یک DocumentCreator ساخته می‌شوند و ساختار مشابهی خواهند داشت. برنامه زیرشاخه تنها نیاز است بداند که چگونه یک کلاس از نوع Letter یا Resume را که از کارخانه می‌گیرد استفاده کند.

کارخانه محل کلاس‌های متشابه داخل کد که اشیاء از آنها ساخته می‌شوند می‌باشد. هدف پیاده‌سازی الگو جداسازی ساخت اشیاء از استفاده‎ آنها و ساخت خانواده‌هایی از اشیاء مرتبط بدون نیاز به وابستگی به نوع کلاس آن‌هاست.

استفاده از این الگو تغییر پیاده‌سازی‌های متفاوت را بدون تغییر برنامه‌هایی که از این پیاده‌سازی‌ها استفاده می‌کنند را ممکن کرده است. هرچند، استفاده از این الگو، مانند الگوهای متشابه، ممکن است باعث پیچیدگی و کار اضافه در نوشتن کد اولیه شود. همچنین جداسازی و انتزاعی کردن در سطح‌های بالا ممکن است موجب امکان اشکال‌زدایی و مراقبت از سامانه‌ها را سخت‌تر بکند.

به طور کلی الگوی Abstract Factory برای ساخت برنامه‌های قابل توسعه و قابل تغییر مفید است. این الگو به برنامه‌نویسان امکان می‌دهد تا برنامه‌های پیچیده را با استفاده از شی‌های ساختاری ساده‌تر و با استفاده از استانداردهای مشترک طراحی کنند.

برای مثال، فرض کنید که یک برنامه نیاز به ساخت شی‌های گوناگونی دارد که هر کدام نیاز به پردازش‌های مختلفی دارند. با استفاده از الگوی Abstract Factory، می‌توان یک کلاس فابریک ایجاد کرد که برای هر نوع شی مورد نیاز، یک شی جدید ایجاد کند و پردازش‌های مختلف را برای آن‌ها انجام دهد. به عنوان مثال، یک الگوی Abstract Factory برای ساخت شی‌های گوناگونی می‌تواند به کار گرفته شود.

تعریف ویرایش

ماهیت کارخانه انتزاعی را می‌توان این طور تعریف کرد که "رابطی برای ساخت خانواده‌ای از اشیاء مرتبط یا وابسته بدون نیاز به مشخص کردن نوع کلاس آن‌ها.[۳]

استفاده ویرایش

کارخانه نوع شیءای که قرار است ساخته بشود را تعیین می‌کند. هرچند که تنها یک شیء از آن را بازمی‌گرداند.

این باعث جلوگیری از ساخت شیء توسط برنامه زیرشاخه می‌شود. برنامه زیر شاخه تنها از کارخانه می‌خواهد تا یک شیء از مدل خواسته شده را برای آن بسازد.[۴]

از آنجایی که کارخانه تنها یک نشانه‌گر به شیء ساخته شده را بازمی‌گرداند برنامه زیرشاخه نمی‌داند که این شیء از کدام کلاس ساخته شده است. پس نوع شی لازم نیست برای برنامه مشتری تعریف شود. در کل این بدین معنی است که:

  • مشتری هیچ دانشی دربارهٔ این که چه مدلی و چه روابطی در شیء به کار رفته است ندارد و تنها یک نسخه ساخته شده از کلاس انتزاعی دریافت می‌کند و تنها از طریق رابط انتزاعی با آن ارتباط دارد.[۵]
  • اضافه کردن انواع جدید کلاس با تنظیم مشتری به استفاده از کارخانه دیگری انجام می‌شود و این بسیار راحت‌تر از آن است که علاوه بر آن‌که کلاس جدید برای مشتری تعریف شود، قسمت‌های مختلف کد مشتری برای سازگاری با کلاس جدید از نوع نوشته شود. اگر تمامی کارخانه‌ها در یک سینگلتون ذخیره شوند کافیست داخل کد از طریق سینگلتون به کارخانه مورد نظر دسترسی پیدا کنیم و این گونه استفاده از کارخانه‌ها بسیار آسان‌تر خواهد بود.[۵]

ساختار ویرایش

نمودار کلاس‌ها ویرایش

 

دستور createButton در رابط GUIFactory یک شی از نوع button دریافت می‌کند و ایده‌ای ندارد که چه پیاده‌سازی از GUIFactory دریافت کرده است.

نمودار کلاسی UML ویرایش

 

نمودار Lepus3 (افسانه) ویرایش

 

شبه کد ویرایش

باید یک کلید در سیستم عامل‌های ویندوز یا مک ایجاد کند. دقت کنید که برنامه هیچ ایده‌ای ندارد که چه نوع GUIFactory و Buttonای به اون می‌دهند.

 method paint()
interface GUIFactory is
 method createButton()
 output: a button
class WinFactory implementing GUIFactory is
 method createButton() is
 output: a Windows button
 Return a new WinButton
class OSXFactory implementing GUIFactory is
 method createButton() is
 output: an OS X button
 Return a new OSXButton
class WinButton implementing Button is
 method paint() is
 Render a button in a Windows style
class OSXButton implementing Button is
 method paint() is
 Render a button in a Mac OS X style
class Application is
 constructor Application(factory) is
 input: the GUIFactory factory used to create buttons
 Button button := factory.createButton()
 button.paint()
Read the configuration file
If the OS specified in the configuration file is Windows, then
 Construct a WinFactory
 Construct an Application with WinFactory
else
 Construct an OSXFactory
 Construct an Application with OSXFactory

C# مثال ویرایش

interface IButton
{
    void Paint();
}

interface IGUIFactory
{
    IButton CreateButton();
}

class WinFactory : IGUIFactory
{
    public IButton CreateButton()
    {
        return new WinButton();
    }
}

class OSXFactory : IGUIFactory
{
    public IButton CreateButton()
    {
        return new OSXButton();
    }
}

class WinButton : IButton
{
    public void Paint()
    {
        //Render a button in a Windows style
    }
}

class OSXButton : IButton
{
    public void Paint()
    {
        //Render a button in a Mac OS X style
    }
}

class Program
{
    static void Main()
    {
        var appearance = Settings.Appearance;

        IGUIFactory factory;
        switch (appearance)
        {
            case Appearance.Win:
                factory = new WinFactory();
                break;
            case Appearance.OSX:
                factory = new OSXFactory();
                break;
            default:
                throw new System.NotImplementedException();
        }

        var button = factory.CreateButton();
        button.Paint();
    }
}

PHP مثال ویرایش

interface ButtonInterface
{
    public function Paint();
}

interface GUIFactoryInterface
{
    public function CreateButton();
}

class WinFactory implements GUIFactoryInterface
{
    public function CreateButton()
    {
        return new WinButton();
    }
}

class OSXFactory implements GUIFactoryInterface
{
    public function CreateButton()
    {
        return new OSXButton();
    }
}

class WinButton implements ButtonInterface
{
    public function Paint()
    {
        echo "Windows Button";
    }
}

class OSXButton implements ButtonInterface
{
    public function Paint()
    {
        echo "OSX Button";
    }
}

$appearance = "osx";

$factory = NULL;

switch ($appearance) {
    case "win":
        $factory = new WinFactory();
        break;
    case "osx":
        $factory = new OSXFactory();
        break;
    default:
        break;
}

$button = $factory->CreateButton();
$button->Paint();

Java مثال ویرایش

public interface IButton {
void paint();
}

public interface IGUIFactory {
public IButton createButton();
}

public class WinFactory implements IGUIFactory {
@Override
public IButton createButton() {
return new WinButton();
}
}

public class OSXFactory implements IGUIFactory {
@Override
public IButton createButton() {
return new OSXButton();
}
}

public class WinButton implements IButton {
@Override
public void paint() {
System.out.println("WinButton");
}
}

public class OSXButton implements IButton {
@Override
public void paint() {
System.out.println("OSX button");
}
}

public class Main {

public static void main(String[] args) throws Exception {
IGUIFactory factory = null;

String appearance = randomAppearance();//current operating system
if (appearance.equals("osx")) {
factory = new OSXFactory();
} else if(appearance.equals("windows")) {
factory = new WinFactory();
} else {
throw new Exception("No such operating system");
}

IButton button = factory.createButton();
button.paint();

}

/**
 * This is just for the sake of testing this program, and doesn't have to do
 * with Abstract Factory pattern.
 * @return
 */
public static String randomAppearance() {
String[] appearanceArr = new String[3];
appearanceArr[0] = "osx";
appearanceArr[1] = "windows";
appearanceArr[2] = "error";
java.util.Random rand = new java.util.Random();
int randNum = rand.nextInt(3);
return appearanceArr[randNum];
}

}

مثال کریستال ویرایش

abstract class Button
  abstract def paint
end

class LinuxButton <Button
  def paint
    "Render a button in a Linux style"
  end
end

class WindowsButton <Button
  def paint
    "Render a button in a Windows style"
  end
end

class MacOSButton <Button
  def paint
    "Render a button in a MacOS style"
  end
end

abstract class GUIFactory
  abstract def create_button : Button
end

class LinuxFactory <GUIFactory
  def create_button
    return LinuxButton.new
  end
end

class WindowsFactory <GUIFactory
  def create_button
    return WindowsButton.new
  end
end

class MacOSFactory <GUIFactory
  def create_button
    return MacOSButton.new
  end
end
# Run program
appearance = "linux"

case appearance
when "linux"
  factory = LinuxFactory.new
when "osx"
  factory = MacOSFactory.new
when "win"
  factory = WindowsFactory.new
end

if factory
  button = factory.create_button
  result = button.paint
  puts result
end

جستارهای وابسته ویرایش

منابع ویرایش

  1. ۱٫۰ ۱٫۱ Freeman, Eric; Robson, Elisabeth; Sierra, Kathy; Bates, Bert (2004). "Head First Design Patterns" (paperback). 1. O'REILLY: 156. ISBN 978-0-596-00712-6. Retrieved 2012-09-12. {{cite journal}}: Cite journal requires |journal= (help)
  2. Freeman, Eric; Robson, Elisabeth; Sierra, Kathy; Bates, Bert (2004). "Head First Design Patterns" (paperback). 1. O'REILLY: 162. ISBN 978-0-596-00712-6. Retrieved 2012-09-12. {{cite journal}}: Cite journal requires |journal= (help)
  3. Gamma, Erich; Richard Helm; Ralph Johnson; John M. Vlissides (2009-10-23). "Design Patterns: Abstract Factory". informIT. Archived from the original on 27 January 2017. Retrieved 2012-05-16. Object Creational: Abstract Factory: Intent: Provide an interface for creating families of related or dependent objects without specifying their concrete classes.{{cite web}}: نگهداری یادکرد:ربات:وضعیت نامعلوم پیوند اصلی (link)
  4. Veeneman, David (2009-10-23). "Object Design for the Perplexed". The Code Project. Archived from the original on 21 February 2011. Retrieved 2012-05-16. The factory insulates the client from changes to the product or how it is created, and it can provide this insulation across objects derived from very different abstract interfaces.{{cite web}}: نگهداری یادکرد:ربات:وضعیت نامعلوم پیوند اصلی (link)
  5. ۵٫۰ ۵٫۱ "Abstract Factory: Implementation". OODesign.com. Retrieved 2012-05-16.