vendredi 11 décembre 2020

Would a design pattern fit this situation or just over complicate things? [closed]

I am trying to become more comfortable with design patterns and when to correctly apply them with out over complicating my code for the sake of using a pattern. So here is a sample that I thought, it's kind of contrived but I hope it helps illustrate my confusion.

The customer types are the same except for "how" they process the lists properties.

I was thinking I could solve this with 1 Customer class and 3 strategies but I am not convinced a pattern will work here. All opinions are welcome :)

 class Program {
        public class AvailableAppointment {
               public DateTime Date { get; set; }
        }

        public class AvailableTime {
            public DateTime Time { get; set; }
        }

        public class VisitTime {
            //Some other properties would be here
            public DateTime Time { get; set; }
        }

        public class VisitDay {
            //Some other properties would be here
            public DateTime VisitDate { get; set; }
        }

        public abstract class Customer {
            public string Name { get; set; }

            private IEnumerable<AvailableAppointment> _availabeAppoinments;
            private IEnumerable<AvailableTime> _availabeTimes;

            public IList<VisitTime> VisitTimes { get; private set; }
            public IList<VisitDay> VisitDays { get; private set; }

            public Customer(IEnumerable<AvailableAppointment> availabeAppoinments, IEnumerable<AvailableTime> availabeTimes)  {
                _availabeAppoinments = availabeAppoinments;
                _availabeTimes = availabeTimes; ;
            }

            public virtual void GenerateVisitDays(IEnumerable<DateTime> vipSelectedDates) {
                /*Pseudo Code (Apply the business rules) 

                1) Visit Days must fall in the Available Appointments List of Dates
                2) Certain customers can only pick certain days based on some rules but must still satisfy rule #1
                    - Standard Customer gets 2 days selected by the system  
                    - General Customers gets alternating days from the first day in the appoitment day list
                    - VIP Customer pick all days or any combination of days
                */
            }

            public virtual void GenerateVisitDays() {
                /*Pseudo Code (Apply the business rules) 

                1) Visit Days must fall in the Available Appointments List of Dates
                2) Certain customers can only pick certain days based on some rules but must still satisfy rule #1
                    - Standard Customer gets 2 days selected by the system  
                    - General Customers gets alternating days from the first day in the appoitment day list
                    - VIP Customer pick all days or any combination of days
                */
            }

            public virtual void GenerateVisitTimes() {
                /* Pseudo Code (Apply the business rules) 

                1) Visit Times must fall in the Available Times List of Dates
                2) Certain customers can only pick certain times based on some rules but must still satisfy rule #1
                    - Standard Customer can pick up to 2 times a day
                    - General Customers can pick alternating times 
                    - VIP Customer can pick all times or any combination of times
                */
            }

            public virtual void GenerateVisitTimes(IEnumerable<DateTime> vipSelectedTimes) {
                /* Pseudo Code (Apply the business rules) 

                1) Visit Times must fall in the Available Times List of Dates
                2) Certain customers can only pick certain times based on some rules but must still satisfy rule #1
                    - Standard Customer can pick up to 2 times a day
                    - General Customers can pick alternating times 
                    - VIP Customer can pick all times or any combination of times
                */
            }
        }

        public class StandardCustomer : Customer {

            public StandardCustomer(IEnumerable<AvailableAppointment> availabeAppoinments, IEnumerable<AvailableTime> availabeTimes) : base(availabeAppoinments, availabeTimes) {

            }
            public override void GenerateVisitDays() {
                //Override this method to meet Standard Customer requirements
            }
            public override void GenerateVisitTimes() {
                //Override this method to meet Standard Customer requirements
            }
        }

        public class GeneralCustomer : Customer {

            public GeneralCustomer(IEnumerable<AvailableAppointment> availabeAppoinments, IEnumerable<AvailableTime> availabeTimes) : base(availabeAppoinments, availabeTimes) {

            }
            public override void GenerateVisitTimes() {
                //Override this method to meet General Customer requirements
            }
            public override void GenerateVisitDays(IEnumerable<DateTime> vipSelectedDates) {
                //Override this method to meet General Customer requirements
            }
        }

        public class VipCustomer : Customer {

            public VipCustomer(IEnumerable<AvailableAppointment> availabeAppoinments, IEnumerable<AvailableTime> availabeTimes) : base(availabeAppoinments, availabeTimes) {

            }

            public void GenerateVisitDays(IEnumerable<DateTime> selectedDays) {
                //This method has the same code as the other customer types but with some minor additional logic
                //that pertains to a VIP Customer.
            }
            public void GenerateVisitTimes(IEnumerable<DateTime> selectedTimes) {
                //This method has the same code as the other customer types but with some minor additional logic
                //that pertains to a VIP Customer.
            }
        }

        public class CustomerFactory {
            public static T CreateCustomer<T>(params object[] constructorArguments) where T : Customer{
                Type type = typeof(T);
                Object obj = Activator.CreateInstance(type, constructorArguments);
                return (T)obj;
            }
        }

        static void Main(string[] args) {

            /* I would like to come up with away to call these customer methods polymorphically so the UI does not
             * have know about the concrete type.
             * 
             * 
             * I am not happy that either the UI has to know about the contrete type VIPCustomer and that I have a overload
             * in the base class just to suit the VIP Customer
             * 
             * OR 
             * 
             * That I have to make custom methods for the VIPCustomer 
             * 
             * 
             * Is there a pattern that I could apply to solve my 2 concerns?
             * 
             * 1) Strategy pattern doesn't work because the method signature needs to change
             * 2) Visitor pattern doesn't really apply because a specific algorithm only applies to a single type.
             * 
             */


            var listOfAppointments = new List<AvailableAppointment>();
            var listOfAvailableTimes = new List<AvailableTime>();

            Customer customer1 = CustomerFactory.CreateCustomer<StandardCustomer>(listOfAppointments, listOfAvailableTimes);
            customer1.GenerateVisitDays();
            customer1.GenerateVisitTimes();

            Customer customer2 = CustomerFactory.CreateCustomer<GeneralCustomer>(listOfAppointments, listOfAvailableTimes);
            customer2.GenerateVisitDays();
            customer2.GenerateVisitTimes();


            IEnumerable<DateTime> vipSelectedDates = new List<DateTime>();
            var vipSelectedTimes = new List<DateTime>();
            Customer customer3 = CustomerFactory.CreateCustomer<VipCustomer>(listOfAppointments, listOfAvailableTimes);

            /* Here is where I get crippled by choice! 
               -Just add the overloads for the VIP type to the base class
                    customer3.GenerateVisitDays(vipSelectedDates);
                    customer3.GenerateVisitTimes(vipSelectedTimes);
               OR
               -Create custom methods just for the VIP concrete type?
                    customer3.BuildVipDays(vipSelectedDates);
                    customer3.BuildVipTimes(vipSelectedTimes);
            */          
            Console.ReadKey();
        }
    }

Aucun commentaire:

Enregistrer un commentaire