سؤال

لقد قمت ببعض القراءة على نمط الإستراتيجية ، ولدي سؤال. لقد قمت بتطبيق تطبيق وحدة تحكم أساسية للغاية أدناه لشرح ما أطلبه.

لقد قرأت أن عبارات "التبديل" هي علامة حمراء عند تنفيذ نمط الاستراتيجية. ومع ذلك ، لا يمكنني الابتعاد عن وجود بيان التبديل في هذا المثال. هل فاتني شيء؟ تمكنت من إزالة المنطق من قلم, ولكن بلدي الأساسية لديه بيان التبديل فيه الآن. أفهم أنه يمكنني بسهولة إنشاء جديد Triangledrawer الطبقة ، ولن تضطر إلى فتح قلم الفصل ، وهو أمر جيد. ومع ذلك ، سأحتاج إلى فتح الأساسية بحيث يعرف أي نوع من Idrawer لتمرير إلى قلم. هل هذا فقط ما يجب القيام به إذا كنت أعتمد على المستخدم للإدخال؟ إذا كانت هناك طريقة للقيام بذلك دون بيان التبديل ، أحب أن أراها!

class Program
{
    public class Pencil
    {
        private IDraw drawer;

        public Pencil(IDraw iDrawer)
        {
            drawer = iDrawer;
        }

        public void Draw()
        {
            drawer.Draw();
        }
    }

    public interface IDraw
    {
        void Draw();
    }

    public class CircleDrawer : IDraw
    {
        public void Draw()
        {
            Console.Write("()\n");
        }
    }

    public class SquareDrawer : IDraw
    {
        public void Draw()
        {
            Console.WriteLine("[]\n");
        }
    }

    static void Main(string[] args)
    {
        Console.WriteLine("What would you like to draw? 1:Circle or 2:Sqaure");

        int input;
        if (int.TryParse(Console.ReadLine(), out input))
        {
            Pencil pencil = null;

            switch (input)
            {
                case 1:
                    pencil = new Pencil(new CircleDrawer());
                    break;
                case 2:
                    pencil = new Pencil(new SquareDrawer());
                    break;
                default:
                    return;
            }

            pencil.Draw();

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }
}

الحل المطبق الموضح أدناه (شكرًا لجميع الذين استجابوا!) هذا الحل وصلني إلى النقطة التي يجب أن أفعلها لاستخدام جديد ط رسم الكائن هو إنشائها.

public class Pencil
    {
        private IDraw drawer;

        public Pencil(IDraw iDrawer)
        {
            drawer = iDrawer;
        }

        public void Draw()
        {
            drawer.Draw();
        }
    }

    public interface IDraw
    {
        int ID { get; }
        void Draw();
    }

    public class CircleDrawer : IDraw
    {

        public void Draw()
        {
            Console.Write("()\n");
        }

        public int ID
        {
            get { return 1; }
        }
    }

    public class SquareDrawer : IDraw
    {
        public void Draw()
        {
            Console.WriteLine("[]\n");
        }

        public int ID
        {
            get { return 2; }
        }
    }

    public static class DrawingBuilderFactor
    {
        private static List<IDraw> drawers = new List<IDraw>();

        public static IDraw GetDrawer(int drawerId)
        {
            if (drawers.Count == 0)
            {
                drawers =  Assembly.GetExecutingAssembly()
                                   .GetTypes()
                                   .Where(type => typeof(IDraw).IsAssignableFrom(type) && type.IsClass)
                                   .Select(type => Activator.CreateInstance(type))
                                   .Cast<IDraw>()
                                   .ToList();
            }

            return drawers.Where(drawer => drawer.ID == drawerId).FirstOrDefault();
        }
    }

    static void Main(string[] args)
    {
        int input = 1;

        while (input != 0)
        {
            Console.WriteLine("What would you like to draw? 1:Circle or 2:Sqaure");

            if (int.TryParse(Console.ReadLine(), out input))
            {
                Pencil pencil = null;

                IDraw drawer = DrawingBuilderFactor.GetDrawer(input);

                pencil = new Pencil(drawer); 
                pencil.Draw();
            }
        }
    }
هل كانت مفيدة؟

المحلول

الإستراتيجية ليست حلًا سحريًا لمكافحة التبديل. ما يفعل

  • منطق عملك معزول ومفتوح للتمديد
  • لديك خيارات بالنسبة لكيفية إنشاء فصول الخرسانة الخاصة بك (انظر أنماط المصنع على سبيل المثال)
  • يمكن أن يكون رمز البنية التحتية الخاصة بك (الرئيسي) نظيفًا جدًا ، خاليًا من كليهما

وض هو تنفيذ هذا الاختيار.

نصائح أخرى

فيما يلي حل هندسي لمشكلتك فقط من أجل تجنب if/switch صياغات.

CircleFactory: IDrawFactory
{
  string Key { get; }
  IDraw Create();
}

TriangleFactory: IDrawFactory
{
  string Key { get; }
  IDraw Create();
}

DrawFactory
{
   List<IDrawFactory> Factories { get; }
   IDraw Create(string key)
   {
      var factory = Factories.FirstOrDefault(f=>f.Key.Equals(key));
      if (factory == null)
          throw new ArgumentException();
      return factory.Create();
   }
}

void Main()
{
    DrawFactory factory = new DrawFactory();
    factory.Create("circle");
}

لا أعتقد أن التبديل الخاص بك هنا في التطبيق التجريبي الخاص بك هو في الواقع جزء من نمط الإستراتيجية نفسه ، فهو يستخدم فقط لممارسة الاستراتيجيتين المختلفين اللذين حددتهما.

يشير تحذير "المفاتيح كونها علامة حمراء" إلى وجود مفاتيح داخل الاستراتيجية؛ على سبيل المثال ، إذا قمت بتعريف استراتيجية "GenericDrawer" ، وحددت ما إذا كان المستخدم يريد مرفوعًا أو circledrawer داخليًا باستخدام مفتاح مقابل قيمة المعلمة ، فلن تحصل على فائدة نمط الاستراتيجية.

يمكنك أيضا التخلص من if بمساعدة القاموس

Dictionary<string, Func<IDraw> factory> drawFactories = new Dictionary<string, Func<IDraw> factory>() { {"circle", f=> new CircleDraw()}, {"square", f=> new SquareDraw()}}();

Func<IDraw> factory;
drawFactories.TryGetValue("circle", out factory);

IDraw draw = factory();

قليلاً إلى وقت متأخر ولكن لأي شخص لا يزال مهتمًا بإزالة بيان مشروط بالكامل.

     class Program
     {
        Lazy<Dictionary<Enum, Func<IStrategy>>> dictionary = new Lazy<Dictionary<Enum, Func<IStrategy>>>(
            () =>
                new Dictionary<Enum, Func<IStrategy>>()
                {
                    { Enum.StrategyA,  () => { return new StrategyA(); } },
                    { Enum.StrategyB,  () => { return new StrategyB(); } }
                }
            );

        IStrategy _strategy;

        IStrategy Client(Enum enu)
        {
            Func<IStrategy> _func
            if (dictionary.Value.TryGetValue(enu, out _func ))
            {
                _strategy = _func.Invoke();
            }

            return _strategy ?? default(IStrategy);
        }

        static void Main(string[] args)
        {
            Program p = new Program();

            var x = p.Client(Enum.StrategyB);
            x.Create();
        }
    }

    public enum Enum : int
    {
        StrategyA = 1,
        StrategyB = 2
    }

    public interface IStrategy
    {
        void Create();
    }
    public class StrategyA : IStrategy
    {
        public void Create()
        {
            Console.WriteLine("A");
        }
    }
    public class StrategyB : IStrategy
    {
        public void Create()
        {
            Console.WriteLine("B");
        }
    }
IReadOnlyDictionaru<SomeEnum, Action<T1,T2,T3,T3,T5,T6,T7>> _actions 
{
    get => new Dictionary<SomeEnum, Action<T1,T2,T3,T3,T5,T6,T7>> 
        {
           {SomeEnum.Do, OptionIsDo},
           {SomeEnum.NoDo, OptionIsNoDo}
        } 
}

public void DoSomething(SomeEnum option)
{
    _action[option](1,"a", null, DateTime.Now(), 0.5m, null, 'a'); // _action[option].Invoke(1,"a", null, DateTime.Now(), 0.5m, null, 'a');
}


pub void OptionIsDo(int a, string b, object c, DateTime d, decimal e, object f, char c)
{
   return ;
}

pub void OptionIsNoDo(int a, string b, object c, DateTime d, decimal e, object f, char c)
{
   return ;
}

في حال لم تكن بحاجة إلى تعدد الأشكال. يستخدم المثال الإجراء ولكن يمكن تمرير أي نوع مندوب آخر. Func إذا كنت ترغب في إعادة شيء ما

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top