欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

几种常见设计模式在项目中的应用

程序员文章站 2023-10-29 08:35:16
一、前言 前几天阅读一框架文档,里面有一段这样的描述 “从对象工厂中………” ,促使写下本文。尽管一些模式简单和简单,但是常用、有用。 结合最近一个项目场景回顾一下里面应用到的一些模式。 Singleton:创建型模式,负责创建维护一个全局唯一 ......

一、前言

  前几天阅读一框架文档,里面有一段这样的描述 “从对象工厂中………” ,促使写下本文。尽管一些模式简单和简单,但是常用、有用。

  结合最近一个项目场景回顾一下里面应用到的一些模式<singleton、factory、strategy>。

  singleton:创建型模式,负责创建维护一个全局唯一实例

  factory:创建型模式,对象工厂负责根据标识创建或获取具体的实例对象

  strategy:行为型/运行时模式,策略负责根据标识控制应用运行时的行为

  示例代码:https://github.com/shawn-china/designpatterndemo.git

二、场景上下文

  项目需求/场景:通过增加辅助工具使用脚本程序对特定应用程序进行“自动化测试”,内容包括:点击按钮、选择菜单、读取控件内容等。

  原始实现:脚本程序<autoit>通过计算坐标的方式对特定应用程序进行“自动化测试”。缺点:脚本程序工作量大、依赖按钮屏幕坐标、坐标计算繁杂、依赖屏幕分辨率等。

  

  目标程序简化图:

几种常见设计模式在项目中的应用<Singleton、Factory、Strategy>

 

图1 目标程序

  使用辅助工具前 :

几种常见设计模式在项目中的应用<Singleton、Factory、Strategy>

 

图2 未使用辅助工具

  

  使用辅助工具后:

几种常见设计模式在项目中的应用<Singleton、Factory、Strategy>

 

图3 使用辅助工具

 

 

三、分析、设计 

  这里只对 辅助工具 进行分析设计,其它略过。 

  1、图1 目标程序有以下主要特点:

    • 目标程序分为 a-e五个功能区

    • 每个功能区有按钮、菜单等相似功能

    • 每个功能区有特有功能

  2、辅助工具对外提供统一调用

  3、辅助工具可以被重复调用,但不支持并发操作

 

  基于以上分析:

    1、将 operator <操控代码或具体操控行为>分为五个具体的 operator 分别为: aoperator 、boperator 、coperator 、doperator 、eoperator ,分别对应操作不同的应用程序区域。

    2、使用创建型模式管理 operator  

    3、使用锁机制,限制并发

    4、外层封装一个单例

    

四、uml  

 几种常见设计模式在项目中的应用<Singleton、Factory、Strategy>

 

 

 

图4 uml类图

   

五、code show

   1、auxiliarytoolsingleton 对外提供调用,并用锁机制控制并发。

using system;
using system.threading;
using designpatterndemo.operator;

namespace designpatterndemo
{
    public class auxiliarytoolsingleton
    {
        public static semaphore operatorsemaphore = new semaphore(1, 1);
        private static readonly object operatorlock = new object();

        public static auxiliarytoolsingleton instance = new auxiliarytoolsingleton();
        private auxiliarytoolsingleton()
        {
            registoroperator(operatorfactory.instance);
        }

        public void calloperator(string operatorname, params string[] operatorparams)
        {
            //operatorsemaphore.waitone();
            lock (operatorlock)
            {
                console.writeline($"call method calloperator :{operatorname} .current thread:{thread.currentthread.managedthreadid}");

                baseoperator concreteoperator = operatorfactory.instance.getoperator(operatorname);
                concreteoperator.initializationparameters(operatorparams);
                concreteoperator.execute();
            }

            //operatorsemaphore.release();
        }

        public static void registoroperator(operatorfactory factory)
        {
            factory.register(nameof(aoperator), new aoperator());
            factory.register(nameof(boperator), new boperator());
            factory.register(nameof(coperator), new coperator());
            factory.register(nameof(doperator), new doperator());
            factory.register(nameof(eoperator), new eoperator());
        }
    }
}

   2、baseoperator 操控基类,包含一些公共方法、虚方法、参数信息。

using system;
using system.threading;

namespace designpatterndemo.operator
{
    public class baseoperator
    {
        public string name { get; set; }
        public string description { get; set; }

        public void execute()
        {
            //todo
            thread.sleep(new random().next(0, 5) * 1000);
            console.writeline($"execute concrete operator:{gettype().name} .current thread:{thread.currentthread.managedthreadid}");
            concreteoperate($"{gettype().name}");
        }
        public void initializationparameters(params string[] operatorparams)
        {
            //todo

            console.writeline($"initialization parameters :{gettype().name}");
        }
        private void concreteoperate(string mark)
        {
            // todo
            console.writeline($"the concrete operation :{mark} was performed successfully .\r\n");
        }
        public virtual void clickbuttonbymark(string mark)
        {
            // todo
            concreteoperate(mark);
        }

        public virtual void clickpopupmenubymark(string mark)
        {
            // todo
            concreteoperate(mark);
        }

        public virtual void selectdropdownboxbyindex(int dropboxindex)
        {
            // todo
            concreteoperate($"{dropboxindex}");
        }
    }
}

  3、aoperator 具体操控类<比如点击按钮>,实现ispecialoperatea, 继承baseoperator 。

using system;

namespace designpatterndemo.operator
{
    public class aoperator : baseoperator, ispecialoperatea
    {
        public void setcontent(string content)
        {
            //todo
            console.writeline($"filled the content:{content} successfully");
        }
        public string getcontent()
        {
            //todo
            return $"{new random().next()}{guid.newguid()}";
        }
    }
}

namespace designpatterndemo.operator
{
    public interface ispecialoperatea
    {
        void setcontent(string content);
        string getcontent();
    }
}

  4、boperator 、coperator 、doperator 具体操控类

namespace designpatterndemo.operator
{
    public class boperator : baseoperator
    {
    }
}

namespace designpatterndemo.operator
{
    public class coperator : baseoperator
    {
    }
}

namespace designpatterndemo.operator
{
    public class doperator : baseoperator
    {
    }
}

  5、eoperator 具体操控类<比如操控树形控件>,实现ispecialoperatee, 继承baseoperator 。

using system;

namespace designpatterndemo.operator
{
    public class eoperator : baseoperator, ispecialoperatee
    {
        public void clicktreeviewbymark(string mark)
        {
            //todo
            console.writeline($"{mark}: execution succeed");
        }
    }
}

namespace designpatterndemo.operator
{
    public interface ispecialoperatee
    {
        void clicktreeviewbymark(string mark);
    }
}

  6、factory 工厂类基类,可根据key注册、删除、获取具体类。创建型模式的一种。

using system.collections.generic;

namespace designpatterndemo
{
    public class factory<tf, tv> where tf : new()
    {
        protected factory()
        {
            keyvalues = new dictionary<string, tv>();
        }

        public static tf instance { get; set; } = new tf();

        private dictionary<string, tv> keyvalues { get; }

        public tv getitem(string key)
        {
            keyvalues.trygetvalue(key, out tv find);

            return find;
        }
        public void register(string key, tv t)
        {
            unregister(key);
            keyvalues.add(key, t);
        }

        public void unregister(string key)
        {
            if (keyvalues.containskey(key)) keyvalues.remove(key);
        }
    }
}

  7、operatorfactory 具体工厂,继承factory 。

using designpatterndemo.operator;

namespace designpatterndemo
{
    public class operatorfactory : factory<operatorfactory, baseoperator>
    {
        public baseoperator getoperator(string operatorname)
        {
            return getitem(operatorname);
        }
    }
}

  8、program 控制台程序,分别使用并行库和task 多线程调用模拟。

using system;
using system.collections.generic;
using system.threading.tasks;
using designpatterndemo.operator;

namespace designpatterndemo
{
    internal class program
    {
        private static void main(string[] args)
        {
            console.writeline("hello world!");

            list<string> concreteoperators = getconcreteoperators();

            parallel.foreach(concreteoperators, current => { calloperator(current); });

            foreach (string operatorname in concreteoperators)
            {
                task concretetask = new task(() => { calloperator(operatorname); });
                concretetask.start();
            }

            console.readkey();
        }
        private static list<string> getconcreteoperators()
        {
            list<string> concreteoperators = new list<string>
            {
                nameof(aoperator),
                nameof(boperator),
                nameof(coperator),
                nameof(doperator),
                nameof(eoperator)
            };
            return concreteoperators;
        }

        private static void calloperator(string operatorname, params string[] operatorparams)
        {
            auxiliarytoolsingleton auxiliarytool = auxiliarytoolsingleton.instance;
            auxiliarytool.calloperator(operatorname, operatorparams);
        }
    }
}

 

六、说明、小结

  1、本文只是为了说明回顾一些模式的使用、原始项目的业务、代码结构、实现语言均作了更换或简化。

  2、uml 所描述,可以使用任何oo语言实现。

  3、如果条件判断很多可以使用:“表驱动法”、strategy pattern 规避。

  4、模式套路与之相应的场景。

  5、demo 代码环境: vs2017 .net core2.2