Factory Pattern without a Switch or If/Then

前端 未结 4 1646
离开以前
离开以前 2021-01-30 14:29

I\'m looking for a simple example of how to implement a factory class, but without the use of a Switch or an If-Then statement. All the examples I can find use one. F

相关标签:
4条回答
  • 2021-01-30 14:49

    Why overcomplicate things? Here is one simple solution:

    using System;
    using System.Collections.Generic;
    
    class Program
    {
        interface IPosition
        {
            string Title { get; }
        }
    
        class Manager : IPosition
        {
            public string Title
            {
                get { return "Manager"; }
            }
        }
    
        class Clerk : IPosition
        {
            public string Title
            {
                get { return "Clerk"; }
            }
        }
    
        class Programmer : IPosition
        {
            public string Title
            {
                get { return "Programmer"; }
            }
        }
    
        class Factory
        {
            private List<IPosition> positions = new List<IPosition>();
            public Factory()
            {
                positions.Add(new Manager());
                positions.Add(new Clerk());
                positions.Add(new Programmer());
                positions.Add(new Programmer());
            }
    
            public IPosition GetPositions(int id)
            {
                return positions[id];
            }
        }
    
        static void Main(string[] args)
        {
            Factory factory = new Factory();
    
            for (int i = 0; i <= 2; i++)
            {
                var position = factory.GetPositions(i);
                Console.WriteLine("Where id = {0}, position = {1} ", i, position.Title);
            }
            Console.ReadLine();
        }
    }
    

    Here is how to do this without using factory class at all:

    using System;
    using System.Collections.Generic;
    
    class Program
    {
        interface IPosition
        {
            string Title { get; }
        }
    
        class Manager : IPosition
        {
            public string Title
            {
                get { return "Manager"; }
            }
        }
    
        class Clerk : IPosition
        {
            public string Title
            {
                get { return "Clerk"; }
            }
        }
    
        class Programmer : IPosition
        {
            public string Title
            {
                get { return "Programmer"; }
            }
        }
    
        static void Main(string[] args)
        {
            List<IPosition> positions = new List<IPosition> { new Manager(), new Clerk(), new Programmer(), new Programmer() };
    
            for (int i = 0; i <= 2; i++)
            {
                var position = positions[i];
                Console.WriteLine("Where id = {0}, position = {1} ", i, position.Title);
            }
            Console.ReadLine();
        }
    }
    
    0 讨论(0)
  • 2021-01-30 14:51

    You could make use of custom attributes and reflection.

    [PositionType(1)]
    class Manager : Position
    {
        public override string Title
        {
            get
            { return "Manager"; }
        }
    }
    
    [PositionType(2)]
    class Clerk : Position
    {
        public override string Title
        {
            get
            { return "Clerk"; }
        }
    }
    

    In your factory you could then get all classes that inherit from Position and find the one that has the PositionType attribute with the correct value.

    static class Factory
    {
        public static Position Get(int id)
        {
            var types = typeof(Position).Assembly.GetTypes()
                .Where(t => !t.IsAbstract && t.IsSubclassOf(typeof(Position)))
                .ToList();
    
            Position position = null;
            foreach(var type in types)
            {
               type.GetCustomAttributes<PositionTypeAttribute>();
    
               if(type.PositionId == id)
               {
                   position = Activator.CreateInstance(type) as Position;
                   break;
               }
            }
    
            if(position == null)
            {
                var message = $"Could not find a Position to create for id {id}.";
                throw new NotSupportedException(message);
            }
    
            return position;
        }
    }
    
    0 讨论(0)
  • 2021-01-30 15:01
    public class PositionFactory
    {
        private Dictionary<int, Type> _positions;
    
        public PositionFactory()
        {
            _positions = new Dictionary<int, Type>();
        }
    
        public void RegisterPosition<PositionType>(int id) where PositionType : Position
        {
            _positions.Add(id, typeof(PositionType));
        }
    
        public Position Get(int id)
        {
            return (Position) Activator.CreateInstance(_positions[id]);
        }
    }
    

    Used like this:

                var factory = new PositionFactory();
                factory.RegisterPosition<Manager>(0);
                factory.RegisterPosition<Clerk>(1);
    
                Position p = factory.Get(0); //Returns a new Manager instance
    
    0 讨论(0)
  • 2021-01-30 15:15

    How about this (no Dictionary required and note that you will get an syntax error if your try to Create<Position>()):

    EDIT - Updated to use an IPosition interface implemented explicitly. Only instances of IPosition can access the member functions (e.g. <implementation of Manager>.Title will not compile).

    EDIT #2 Factory.Create should return an IPosition not T when using the interface properly.

    using System;
    using System.Collections.Generic;
    
    class Program
    {
        interface IPosition
        {
            string Title { get; }
            bool RequestVacation();
        }
    
        class Manager : IPosition
        {
             string IPosition.Title
            {
                get { return "Manager"; }
            }
    
            bool IPosition.RequestVacation()
            {
                return true;
            }
        }
    
        class Clerk : IPosition
        {
            int m_VacationDaysRemaining = 1;
    
            string IPosition.Title
            {
                get { return "Clerk"; }
            }
    
            bool IPosition.RequestVacation()
            {
                if (m_VacationDaysRemaining <= 0)
                {
                    return false;
                }
                else
                {
                    m_VacationDaysRemaining--;
                    return true;
                }
            }
        }
    
        class Programmer : IPosition
        {
            string IPosition.Title
            {
                get { return "Programmer"; }
            }
    
            bool IPosition.RequestVacation()
            {
                return false;
            }
        }
    
        static class Factory
        {
            public static IPosition Create<T>() where T : IPosition, new ()
            {
                return new T();
            }
        }
    
        static void Main(string[] args)
        {
            List<IPosition> positions = new List<IPosition>(3);
            positions.Add(Factory.Create<Manager>());
            positions.Add(Factory.Create<Clerk>());
            positions.Add(Factory.Create<Programmer>());
    
            foreach (IPosition p in positions) { Console.WriteLine(p.Title);  }
            Console.WriteLine();
    
            Random rnd = new Random(0);
            for (int i = 0; i < 10; i++)
            {
                int index = rnd.Next(3);
                Console.WriteLine("Title: {0}, Request Granted: {1}", positions[index].Title, positions[index].RequestVacation());
            }
    
            Console.ReadLine();
        }
    }
    
    0 讨论(0)
提交回复
热议问题