코딩 공부/디자인패턴

반복자 패턴, 컴포지트 패턴

공부를 함 2024. 12. 5. 18:41

Iterator pattern

#region Menu
public class MenuItem
{
    public string Name { get; }
    public string Description { get; }
    public bool IsVegetarian { get; }
    public decimal Price { get; }
    
    public MenuItem(string name, string description, bool isVegetarian, decimal price)
    {
        Name = name;
        Description = description;
        IsVegetarian = isVegetarian;
        Price = price;
    }
}

public class PancakeMenu
{
    private List<MenuItem> menuItems = new List<MenuItem>();

    public PancakeMenu()
    {
        menuItems.Add(new MenuItem("a", "111", false, 2.99m));
        menuItems.Add(new MenuItem("b", "222", false, 2.99m));
        menuItems.Add(new MenuItem("c", "333", true, 3.49m));
        menuItems.Add(new MenuItem("d", "444", true, 3.59m));
    }
    public void AddItem(MenuItem item) { menuItems.Add(item); }
    public void RemoveItem(MenuItem item) { menuItems.Remove(item); }
    public Iterator CreateIterator() { return new PancakeMenuIterator(menuItems); }
}

public class DinerMenu
{
    private readonly int MAX_ITEMS = 6;
    private int numberOfItems = 0;
    private MenuItem[] menuItems;
    
    public DinerMenu()
    {
        menuItems = new MenuItem[MAX_ITEMS];
        menuItems[0] = new MenuItem("e", "555", true, 2.99m);
        menuItems[1] = new MenuItem("f", "666", false, 2.99m);
        menuItems[2] = new MenuItem("g", "777", false, 3.29m);
        menuItems[3] = new MenuItem("h", "888", false, 3.05m);
    }

    public void AddItem(string name, string description, bool isVegetarian, decimal price)
    {
        if (numberOfItems < MAX_ITEMS)
        {
            menuItems[numberOfItems] = new MenuItem(name, description, isVegetarian, price);
            numberOfItems++;
        }
        else { Console.WriteLine("Sorry, menu is full!"); }
    }
    /*public MenuItem[] GetMenu() { return menuItems; }*/
    public Iterator CreateIterator() { return new DinerMenuIterator(menuItems); }
}
#endregion

#region Iterator
public interface Iterator
{
    public bool hasNext();
    public MenuItem next();
}

public class DinerMenuIterator : Iterator
{
    private readonly MenuItem[] menuItems;
    private int position = 0;
    
    public DinerMenuIterator(MenuItem[] menuItems)
    {
        this.menuItems = menuItems;
    }

    public bool hasNext()
    {
        if( menuItems[position] == null) return false;
        else
            return position < menuItems.Length;
    }

    public MenuItem next()
    {
        return menuItems[position++];
    }
}

public class PancakeMenuIterator : Iterator
{
    private readonly List<MenuItem> menuItems;
    private int position = 0;
    
    public PancakeMenuIterator(List<MenuItem> menuItems)
    {
        this.menuItems = menuItems;
    }
    public bool hasNext() { return position < menuItems.Count; }
    public MenuItem next() { return menuItems[position++]; }
}
#endregion

public class Waitress
{
    PancakeMenu pancakeMenu;
    DinerMenu dinerMenu;

    public Waitress(PancakeMenu pancakeMenu, DinerMenu dinerMenu)
    {
        this.pancakeMenu = pancakeMenu;
        this.dinerMenu = dinerMenu;
    }

    public void PrintMenu()
    {
        Iterator pancakeIterator = pancakeMenu.CreateIterator();
        Iterator dinerIterator = dinerMenu.CreateIterator();
        
        Console.WriteLine("MENU\n----\nBREAKFAST");
        PrintMenu(pancakeIterator);
        Console.WriteLine("\nLUNCH");
        PrintMenu(dinerIterator);
    }

    private void PrintMenu(Iterator iterator)
    {
        while (iterator.hasNext())
        {
            MenuItem item = iterator.next();
            Console.WriteLine($"{item.Name}, {item.Price:F2} -- {item.Description}");
        }
    }
}

public class TestDrive
{
    public static void Main(string[] args)
    {
        PancakeMenu pancakeMenu = new PancakeMenu();
        DinerMenu dinerMenu = new DinerMenu();
        Waitress waitress = new Waitress(pancakeMenu, dinerMenu);
        waitress.PrintMenu();
    }
}

 

 

어셈블리에서 지원하는 반복자의 경우 IEnumerator<>를 반환형으로, Collection.GetEnumerator()를 사용하면 되는 것 같다.

Diner은 Iterable이 아니어서 Iterator를 직접 구현했다.

#region Menu
using System.Collections;
public class MenuItem
{
    public string Name { get; }
    public string Description { get; }
    public bool IsVegetarian { get; }
    public decimal Price { get; }
    
    public MenuItem(string name, string description, bool isVegetarian, decimal price)
    {
        Name = name;
        Description = description;
        IsVegetarian = isVegetarian;
        Price = price;
    }
}

public interface IMenu
{
    public void AddItem(MenuItem item);
    public void RemoveItem(MenuItem item);

    public abstract IEnumerator<MenuItem> CreateIterator();
}

public class PancakeMenu : IMenu
{
    private List<MenuItem> menuItems = new List<MenuItem>();

    public PancakeMenu()
    {
        menuItems.Add(new MenuItem("a", "111", false, 2.99m));
        menuItems.Add(new MenuItem("b", "222", false, 2.99m));
        menuItems.Add(new MenuItem("c", "333", true, 3.49m));
        menuItems.Add(new MenuItem("d", "444", true, 3.59m));
    }
    public void AddItem(MenuItem item) { menuItems.Add(item); }
    public void RemoveItem(MenuItem item) { menuItems.Remove(item); }
    public IEnumerator<MenuItem> CreateIterator() { return menuItems.GetEnumerator(); }
}

public class DinerMenu : IMenu
{
    private readonly int MAX_ITEMS = 6;
    private int numberOfItems = 0;
    private MenuItem[] menuItems;
    
    public DinerMenu()
    {
        menuItems = new MenuItem[MAX_ITEMS];
        menuItems[0] = new MenuItem("e", "555", true, 2.99m);
        menuItems[1] = new MenuItem("f", "666", false, 2.99m);
        menuItems[2] = new MenuItem("g", "777", false, 3.29m);
        menuItems[3] = new MenuItem("h", "888", false, 3.05m);
    }
    
    public void AddItem(string name, string description, bool isVegetarian, decimal price)
    {
        if (numberOfItems < MAX_ITEMS)
        {
            menuItems[numberOfItems] = new MenuItem(name, description, isVegetarian, price);
            numberOfItems++;
        }
        else { Console.WriteLine("Sorry, menu is full!"); }
    }
    public void AddItem(MenuItem item) { throw new NotImplementedException(); }
    public void RemoveItem(MenuItem item) { throw new NotImplementedException(); }
    public IEnumerator<MenuItem> CreateIterator() { return new DinerMenuIterator(menuItems); }
}
#endregion

#region Iterator
public class DinerMenuIterator : IEnumerator<MenuItem>
{
    private readonly MenuItem[] menuItems;
    private int position = 0;
    private object? _current;
    private MenuItem _current1;

    public DinerMenuIterator(MenuItem[] menuItems)
    {
        this.menuItems = menuItems;
    }

    public bool MoveNext()
    {
        if( menuItems[position] == null || position >= menuItems.Length) return false;
        else
        {
            _current = menuItems[position];
            _current1 = menuItems[position];
            position++;
            return true;
        }
    }

    public void Reset()
    {
        throw new NotImplementedException();
    }

    MenuItem IEnumerator<MenuItem>.Current => _current1;

    object? IEnumerator.Current => _current;

    public void Dispose()
    {
        throw new NotImplementedException();
    }
}
#endregion

public class Waitress
{
    IMenu pancakeMenu;
    IMenu dinerMenu;

    public Waitress(IMenu pancakeMenu, IMenu dinerMenu)
    {
        this.pancakeMenu = pancakeMenu;
        this.dinerMenu = dinerMenu;
    }

    public void PrintMenu()
    {
        IEnumerator<MenuItem> pancakeIterator = pancakeMenu.CreateIterator();
        IEnumerator<MenuItem> dinerIterator = dinerMenu.CreateIterator();
        
        Console.WriteLine("MENU\n----\nBREAKFAST");
        PrintMenu(pancakeIterator);
        Console.WriteLine("\nLUNCH");
        PrintMenu(dinerIterator);
    }
    private void PrintMenu(IEnumerator<MenuItem> iterator)
    {
        while (iterator.MoveNext())
        {
            if(iterator.Current == null) break;
            MenuItem item = iterator.Current;
            Console.WriteLine($"{item.Name}, {item.Price:F2} -- {item.Description}");
        }
    }
}

public class TestDrive
{
    public static void Main(string[] args)
    {
        IMenu pancakeMenu = new PancakeMenu();
        IMenu dinerMenu = new DinerMenu();
        Waitress waitress = new Waitress(pancakeMenu, dinerMenu);
        waitress.PrintMenu();
    }
}

 

 

Composite pattern

using System.Collections;
public abstract class MenuComponent
{
    protected List<MenuComponent> menuComponents = new List<MenuComponent>();
    public string Name { get; protected set; } = string.Empty;
    public string Description { get; protected set; } = string.Empty;
    public void Add(MenuComponent menuComponent) { menuComponents.Add(menuComponent); }
    public void Remove(MenuComponent menuComponent) { menuComponents.Remove(menuComponent); }
    public MenuComponent GetChild(int i) { return menuComponents[i]; }
    public virtual void Print() {  }
}
public class MenuItem : MenuComponent
{
    public bool IsVegetarian { get; private set; } = false;
    public decimal Price { get; private set; } = 0.0m;
    
    public MenuItem(string name, string description, bool isVegetarian, decimal price)
    {
        Name = name;
        Description = description;
        IsVegetarian = isVegetarian;
        Price = price;
    }

    public override void Print()
    {
        Console.WriteLine($"{Name}, {PrintVegetarian()} {Price:F2} {PrintDescription()}");
        if(menuComponents.Count > 0)
        {
            Console.WriteLine("+ other options");
            foreach (var menuComponent in menuComponents) menuComponent.Print();
        }
    }
    private string PrintVegetarian() { return IsVegetarian ? " (V) " : "    "; }
    private string PrintDescription() { return Description.Length > 0 ? "-- " + Description : "(no description)"; }
}

public class Menu : MenuComponent
{
    public Menu(string name, string description)
    {
        Name = name;
        Description = description;
    }

    public override void Print()
    {
        Console.WriteLine($"\n{Name}, {Description}\n --------------------------");
        foreach (var menuComponent in menuComponents) menuComponent.Print();
    }
}

public class Waitress
{
    private MenuComponent allMenus;
    public Waitress(MenuComponent allMenus) { this.allMenus = allMenus; }
    public void PrintMenu() { allMenus.Print(); }
}

public class TestDrive
{
    public static void Main(string[] args)
    {
        MenuComponent pancakeHouseMenu = new Menu("[PANCAKE HOUSE MENU]", "Breakfast");
        MenuComponent dinerMenu = new Menu("[DINER MENU]", "Lunch");
        MenuComponent cafeMenu = new Menu("[CAFE MENU]", "Dinner");
        MenuComponent dessertMenu = new Menu("[DESSERT MENU]", "Dessert of course!");
        
        MenuComponent allMenus = new Menu("<ALL MENUS>", "All menus combined");
        allMenus.Add(pancakeHouseMenu);
        allMenus.Add(dinerMenu);
        allMenus.Add(cafeMenu);
        allMenus.Add(dessertMenu);
        
        MenuItem pancake = new MenuItem("Pancakes", "With fried eggs, sausage", false, 2.99m);
        MenuItem waffles = new MenuItem("Waffles", "With your choice of blueberries or strawberries", true, 3.59m);
        MenuItem eggsBaconMushroom = new MenuItem("Eggs, Bacon and Mushroom", "Simple menu", true, 3.49m);
        MenuItem cake = new MenuItem("Cake", "Chocolate with a chocolate frosting", true, 4.25m);
        MenuItem tea = new MenuItem("Tea", "With hot chocolate", true, 1.50m);
        MenuItem dessert = new MenuItem("Dessert", "Peach puffs and chocolate syrup", false, 2.50m);
        
        pancakeHouseMenu.Add(pancake);
        pancakeHouseMenu.Add(waffles);
        dinerMenu.Add(eggsBaconMushroom);
        cafeMenu.Add(tea);
        dessertMenu.Add(cake);
        dessertMenu.Add(dessert);
        
        waffles.Add(new MenuItem("    Blueberries", "", true, 0.99m));
        waffles.Add(new MenuItem("    Strawberries", "", true, 1.50m));
        dessert.Add(new MenuItem("    Peach puffs", "", true, 1.25m));
        dessert.Add(new MenuItem("    Chocolate syrup", "", true, 1.00m));
        
        
        Waitress waitress = new Waitress(allMenus);
        waitress.PrintMenu();
    }
}

 

 

java의 instancof 키워드는 C#에선 is 키워드다.

해당하는 타입의 인스턴스인지 확인할 수 있다.

public class Animal { }

public class Dog : Animal { }

public class Example
{
    public void CheckType(object obj)
    {
        if (obj is Dog)
        {
            Console.WriteLine("The object is an instance of Dog.");
        }
        else
        {
            Console.WriteLine("The object is not an instance of Dog.");
        }
    }
}

 

'코딩 공부 > 디자인패턴' 카테고리의 다른 글

패턴 정리  (0) 2024.12.09
프록시 패턴  (1) 2024.12.09
템플릿 메소드 패턴  (0) 2024.12.05
어댑터 패턴, 퍼사드 패턴  (1) 2024.12.04
커맨드 패턴  (0) 2024.12.04