设计模式系列-创建者模式

一、上篇回顾

上篇我们主要讲述了抽象工厂模式和工厂模式。并且分析了该模式的应用场景和一些优缺点,并且给出了一些实现的思路和方案,我们现在来回顾一下:

抽象工厂模式:一个工厂负责所有类型对象的创建,支持无缝的新增新的类型对象的创建。这种情况是通过配置文件来实现的,通过字典映射的方式来实现,不过可能效率上有点低下,可以通过优化的方式

来做,上篇中我们也给出了委托的工厂实现形式,相比之前的简单工厂模式和工厂模式有了更好的灵活性,并且对具有依赖关系或者组合关系的对象的创建尤为适合。

上篇中,有不少的朋友提出了一些意见和建议,首先很感谢大伙的支持和鼓励,有朋友提出来,我画的图不够专业,专业人士应该用UML建模图来搞,我怎么说呢?我也同意这样的说法,但是我发现我通过

另外的直观的图形,大家一看就能更明白,结合代码,当然好的UML图,已经能表述清楚设计的思路和大体实现了,不过说实话,我看着就有点类,特别是UML图复杂的时候。所以我还是暂时先用这种一般的图

形来表述我理解的设计模式的思想,看看大伙是什么看法和意见,如果说都说说UML图的话,那么后面的相关模式,我会主要以UML专业图来绘制。

我这里总结下我们以后项目中的可能会用到设计模式 之处或者系统架构的时候,一般情况下有这样的几类方案,我们可以在考虑系统的低耦合性的时候的设计:

image基本上来说能掌握上面的几类情况,基本上设计出来的系统至少是可用的,不知道大家有没有更多意见和建议。有的请提出来,我会备

注在文章中。

二、摘要

本文主要是针对创建型模式中的创建者模式进行讲述,创建者模式是创建型模式中最负责的一个设计模式了,创建者负责构建一个对象的各个部分,并且完成组装的过程,我们可以这么理解创建

者模式,创建者模式类似与一个步骤基本固定,但是每个步骤中的具体形式却又可以变化的这类对象的创建。也许这样说还是太抽象了,我们这么来理解吧,我感觉让人最容易理解的形式还是图形化

的形式,不但接受起来容易,并且让人映象深刻,不知道大家是不是和我有同感呢?下面我们给出一个简单的例子,通过图形化的流程来说明吧:我们这里以我们大伙平时最常见的做饭为例吧:

image可能我这里给出的流程只是我个人理解的或者看到的过程,不代表全部,呵呵,这里只是事例性的说明。

三、本文大纲

a、上篇回顾。

b、摘要。

c、本文大纲。

d、创建者模式的特点及使用场景。

e、创建者模式的实现方案。

f、创建者模式使用总结。

g、系列进度。

h、下篇预告。

四、创建者模式的特点及使用场景

创建者模式主要是用于创建复杂的一些对象,这些对象的创建步骤基本固定,但是可能具体的对象的组成部分却又可以自由的变化,现实中的例子很多,但是可能大伙都比较容易理解的就是,我

们的自己花钱配置的台式机或者笔记本,可以 这样理解,这些硬件设备的各个零件,不管是CPU是Intel的还是AMD的,显卡是华硕的还是小影霸的,不管硬盘是西部数据的还是希捷的,其实想表述

的意思就是对象的具体的组成部分可以是变化的,但是可能我们发现对象的这些组成部分的组织起来的过程是相对固定的,那么我们就可以用创建者模式来做,并且我们引入一个引导者(Director)来

引导这个对象的组装过程。可以简单用图形化的过程来描述如下:

image我们上面说明了一个服装的大概生产过程,这里生产的顺序可能会发生变化,或者

生产的帽子,上衣等都会发生变化,但是服装的组装过程基本上变化不大,都是需要帽子,上衣,裤子的,这时候我们可以通过引导着负责组装这样的过程,然后我们在具体的每个部分可以是抽象接

口,根据不同的实现创建不同的帽子来完成变化。

五、创建者模式的实现方案

5.1、经典的创建者模式实现

  • * 我们先给出经典创建者模式的一个实现形式,然后针对这个经典模式后面提出几个改进方案,我们这里以上面讲述的服装的过程作为例子来说明下创建者模式的原理和思想,希望大家也能灵活的运用到实际的项目中去。达到学以致用的目的。 
    

我们来看看具体的代码实现:

    /// <summary> 
    /// 创建对象组织的所有构造步骤接口 
    /// </summary> 
    public interface IBuider 
    { 
        void BuilderPart1(); 
        void BuilderPart2(); 
        void BuilderPart3(); 
    }

定义一个服装对象:

    /// <summary> 
    /// 服装对象 
    /// </summary> 
    public class Dress 
    { 
        /// <summary> 
        /// 构建帽子 
        /// </summary> 
        public void BuildHat() 
        { 
            throw new NotImplementedException(); 
        } 
        /// <summary> 
        /// 构建上衣 
        /// </summary> 
        public void BuilderWaist() 
        { 
            throw new NotImplementedException(); 
        } 
        /// <summary> 
        /// 构建裤子 
        /// </summary> 
        public void BuilderTrousers() 
        { 
            throw new NotImplementedException(); 
        } 
    }

实现创建对象的具体步骤:

    public class Builder : IBuider 
    { 
         private Dress _dress; 
         public Builder(Dress dress) 
         { 
             this._dress = dress; 
         }
        public void BuilderPart1() 
        { 
            this._dress.BuildHat(); 
        }
        public void BuilderPart2() 
        { 
            this._dress.BuilderWaist(); 
        }
        public void BuilderPart3() 
        { 
            this._dress.BuilderTrousers(); 
        }
        public Dress Build() 
        { 
            return this._dress; 
        } 
    }

通过指导者指导对象的创建,而具体的对象的创建还是靠对象本身提供的相应方法,Builder只是调用对象的方法完成组装步骤。Builder内部提供一个返回构造后完整对象的方法,上面给出的方法是

Build()方法。

    /// <summary> 
    /// 指导者 
    /// </summary> 
    public class Director 
    { 
        public void Build(IBuider builder) 
        { 
            builder.BuilderPart1(); 
            builder.BuilderPart2(); 
            builder.BuilderPart3(); 
        } 
    }

通过上面的代码,我们给出了经典创建者模式的核心代码形式,那么针对上面无疑有以下的几个缺点:

1、Ibuilder接口必须定义完整的组装流程,一旦定义就不能随意的动态修改。

2、Builder与具体的对象之间有一定的依赖关系,当然这里可以通过接口来解耦来实现灵活性。

3、Builder必须知道具体的流程。

那么针对上面的几个问题,我们如何来解决呢?我想前面的创建型模式已经给我了足够的经验,还是通过配置文件或者其他的形式来提供灵活性。

  • 5.2、创建者模式特性+委托实现

针对上面讲述的例子我们可以考虑如下的方式进行改进:

我们先定义一个构造每个对象部分的委托,并且这个方法的参数是动态变化的:

    /// <summary> 
    /// 定义通用的构造部分的委托 
    /// </summary> 
    public delegate void BuildHandler(params object[] items);

我们通过定义标记来标识对象中的每个部分的构造步骤

    /// <summary> 
    /// 为对象中的每个步骤打上标记 
    /// </summary> 
    [AttributeUsage(AttributeTargets.Method,AllowMultiple=false)] 
    public class BuildAttribute : Attribute 
    { 
        private MethodInfo hander; 
        private int stepSort;
        public MethodInfo BuildHandler 
        { 
            get 
            { 
                return this.hander; 
            } 
            set 
            { 
                this.hander = value; 
            } 
        }
        public int StepSort 
        { 
            get 
            { 
                return this.stepSort; 
            } 
            set 
            { 
                this.stepSort = value; 
            } 
        } 
    }

构造对象的统一接口

    /// <summary> 
    /// 创建对象组织的所有构造步骤接口 
    /// </summary> 
    public interface IBuider 
    { 
        void Build<T>() where T : class,new(); 
    }

下面给出具体的Builder的缓存实现方案代码

    public class CommonBuilder : IBuider 
    { 
         /// <summary> 
         /// 缓存每个对象的具体的构造步骤 
         /// </summary> 
         private Dictionary<Type, List<BuildHandler>> steps = null;

        public void Build<T>(T ob) where T : class, new() 
        { 
            //从缓存中读取指定类型的项 
            List<BuildHandler> handlers = steps[typeof(T)];
            foreach (BuildHandler handler in handlers) 
            { 
                handler(); 
            } 
        } 
    }

给出一些获取某个类型内部的所有具有我们的自定义特性标记的MethodInfo列表

        public List<MethodInfo> GetMethodInfoList<T>() where T : class, new() 
        { 
            //从缓存中读取指定类型的项 
            List<MethodInfo> methods = new List<MethodInfo>();
            T target = new T(); 
            MethodInfo[] methodList= typeof(T).GetType().GetMethods(); 
            BuildAttribute[] attributes = null; 
            foreach (MethodInfo info in methodList) 
            { 
               attributes=  (BuildAttribute[])info.GetCustomAttributes(typeof(BuildAttribute), true); 
               if (attributes.Length > 0) 
                   methods.Add(info); 
            }
            return methods; 
        }

获取所有的特性,一般使用这个方法即可获取所有的具有标记该特性的方法列表和相应的步骤:

      public List<BuildAttribute> GetBuildAttributeList<T>() where T : class, new() 
        { 
            List<BuildAttribute> attributes = new List<BuildAttribute>(); 
            BuildAttribute[] attributeList = null; 
            BuildAttribute attribute = null; 
            foreach (MethodInfo info in this.methods) 
            { 
                //设置特性中要执行的方法 
                attributeList = (BuildAttribute[])info.GetCustomAttributes(typeof(BuildAttribute), true); 
                if (attributeList.Length > 0) 
                { 
                    attribute = attributeList[0]; 
                    attribute.BuildHandler = info; 
                    attributes.Add(attribute); 
                } 
            } 
            //缓存步骤 
            steps.Add(typeof(T), attributes);
            return attributes; 
        }

具体的Build中的调用代码实现:

       public T Build<T>(T ob) where T : class, new() 
        { 
            List<BuildAttribute> attributeList = GetBuildAttributeList<T>();
            T target=new T();
            //构造对象的过程 
            foreach (BuildAttribute item in attributeList) 
            { 
                item.BuildHandler.Invoke(target,null); 
            }
            return target; 
        }

这样我们就完成了一个通用的基于标记的自动发现某个类型的标记方法步骤的通用代码实现,可能大家感觉这样的方式还是挺麻烦的,那么我们还有没有更好的改进方案呢?因为每次打标记我还是感

觉挺麻烦的,而且代码量分布的也比较广泛,我想通过统一配置管理的方式,当然也是可以的,那么我们可以通过下面的方式来进行扩展。

  • 5.3、创建者模式配置文件方式实现

配置文件的方式实现创建者,这个怎么说呢,上面的抽象工厂的模式中,我们主要采用了这样的方式来实现配置的灵活性和扩展性,其实创建者也是一样的,我们来看看配置文件吧,我想

就看配置文件就大概知道了,具体的应用代码了,请看下图,粗略描述了实现的思路:

image

我这里给出配置文件的父子级节点示例:

<?xml version="1.0" encoding="utf-8" ?> 
<Build> 
    <BuildClass name="ClassName" type="ClassType"> 
        <BuildStep StepOrder="1" MethodName="MethodName1"/> 
        <BuildStep StepOrder="2" MethodName="MethodName2" /> 
    </BuildClass> 
    <BuildClass name="ClassName1" type="ClassType1"> 
        <BuildStep StepOrder="1" MethodName="MethodName1"/> 
        <BuildStep StepOrder="2" MethodName="MethodName2" /> 
    </BuildClass> 
</Build>

我们这里通过在Build实现中读取配置文件中的所有的步骤,放在字典中。给出示例代码

   /// <summary> 
   /// 创建对象组织的所有构造步骤接口 
   /// </summary> 
   public class Buider : IBuider 
   { 
       private Dictionary<Type, List<MethodInfo>> steps = null;
       public Buider() 
       { 
           steps = new Dictionary<Type, List<MethodInfo>>(); 
           //读取配置文件! 
           //将配置文件中的类名和方法名取出,然后通过反射取到这个类型下的所有方法,根据配置中的步骤和方法名添加到 
           //步骤列表中,然后缓存到字典中 
           steps.Add(Type.GetType(""), new List<MethodInfo>()); 
       }
       public T Build<T>() where T: class,new() 
       { 
           T target = new T();
           //从字典中找到对应的缓存列表,执行构造过程 
           List<MethodInfo> list = steps[typeof(T)];
           //执行构造 
           foreach (MethodInfo info in list) 
           { 
               info.Invoke(target, null); 
           }
           return target; 
       } 
   }

通过上面的几步配置就可以完成相应的构建过程,这时候我们的指导者的工作就简单了,就是只是简单的通过使用Build中的通用方法

    public class Director 
    { 
        public void Build<T>(IBuider builder) where T:class,new() 
        { 
            builder.Build<T>(); 
        } 
    }

只要通过上面的步骤就完成了创建者模式的通用实现方案。

六、创建者模式使用总结

通过上面的给出的几类不同的实现方案我们知道,创建者模式是一个对对象的构建过程“精细化”的构建过程,每个部分的构建可能是变化的,但是对象的组织过程是固定的,通过这种统一的创建方

式,无疑增加了我们设计上的灵活性,当我们在构建复杂对象的时候,我们如果发现每个部分可能都是变化的,并且是多个不同的构建步骤的时候,我们可以考虑使用创建者模式。相比我们之前讲述

的工厂和抽象工厂模式区别还是很大的,我们发现创建者适合这类复杂对象的创建,对于抽象工厂可能就无法完成这样的组装工作,而且创建者模式是把复杂对象的内部创建方法进行调用,组织协调

了对象的各个部分前后顺序的控制。简单的描述创建者就是这样的情况:

image

由于本人水平有限,或者讲述能力有限,表达思路错误或者想法错误,请大家批评指出,如果您有更好的意见或者想法,请提出讨论,欢迎大家提出宝贵意见和建议。

七、系列进度。

创建型

1、系统架构技能之设计模式-单件模式

2、系统架构技能之设计模式-工厂模式

3、系统架构技能之设计模式-抽象工厂模式

4、系统架构技能之设计模式-创建者模式

5、系统架构技能之设计模式-原型模式

结构型

1、系统架构技能之设计模式-组合模式

2、系统架构技能之设计模式-外观模式

3、系统架构技能之设计模式-适配器模式

4、系统架构技能之设计模式-桥模式

5、系统架构技能之设计模式-装饰模式

6、系统架构技能之设计模式-享元模式

7、系统架构技能之设计模式-代理模式

行为型

1、系统架构技能之设计模式-命令模式

2、系统架构技能之设计模式-观察者模式

3、系统架构技能之设计模式-策略模式

4、系统架构技能之设计模式-职责模式

5、系统架构技能之设计模式-模板模式

6、系统架构技能之设计模式-中介者模式

7、系统架构技能之设计模式-解释器模式

八、下篇预告。

下篇将会针对原型模式进行讲述,该模式也是创建型模式中很有特点设计模式之一,该 模式是利用现有的一个对象进行克隆的过程产生一个新的对象,当然这里的复制对象可以是2种,深复制和浅复

制,在这个系列的总结中如果您有好的想法或者创意,请提出来,希望大家多提宝贵意见,错误之处还请指出,请大家继续支持。

转自:https://www.cnblogs.com/hegezhou_hot/archive/2010/12/02/1894771.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/102459.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

centos安装jdk-8u371-linux-x64.tar.gz包

java -version //查看jdk版本 rpm -qa | grep jdk 删除带有"openjdk"字样的jdk 例: rpm -e --nodeps java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64 下载该版本的jdk(jdk-8u371-linux-x64.tar.gz) (https://www.oracle.com/java/technologies/javase/javase8u2…

linux 内存一致性

linux 出现内存一致性的场景 1、编译器优化 &#xff0c;代码上下没有关联的时候&#xff0c;因为编译优化&#xff0c;会有执行执行顺序不一致的问题&#xff08;多核单核都会出现&#xff09; 2、多核cpu乱序执行&#xff0c;cpu的乱序执行导致内存不一致&#xff08;多核出…

MATLAB制图代码【第二版】

MATLAB制图代码【第二版】 文档描述 Code describtion: This code is version 2 used for processing the data from the simulation and experiment. Time : 2023.9.3 Author: PEZHANG 这是在第一版基础上&#xff0c;迭代出的第二版MATLAB制图代码&#xff0c;第二版的特点是…

kvm 虚拟机添加网卡方法

找到kvm虚拟机的配置文件 虚拟机名称.xml kvm虚拟机配置文件默认路径&#xff1a;/etc/libvirt/qemu/ 先停kvm虚拟机 virsh shutdown 虚拟机名称 修改kvm虚拟机配置文件 virsh edit 虚拟机名称 在kvm虚拟机里面配置新增接口如下内容&#xff1a; <interface typebridg…

时序预测 | MATLAB实现CNN-GRU卷积门控循环单元时间序列预测(风电功率预测)

时序预测 | MATLAB实现CNN-GRU卷积门控循环单元时间序列预测&#xff08;风电功率预测&#xff09; 目录 时序预测 | MATLAB实现CNN-GRU卷积门控循环单元时间序列预测&#xff08;风电功率预测&#xff09;预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.时序预测 | MA…

裸露土方智能识别算法 python

裸露土方智能识别算法通过opencvpython网络模型框架算法&#xff0c;裸露土方智能识别算法能够准确识别现场土堆的裸露情况&#xff0c;并对超过40%部分裸露的土堆进行抓拍预警。此次算法用到的Python是一种由Guido van Rossum开发的通用编程语言&#xff0c;它很快就变得非常流…

Unexpected mutation of “xxxx“ prop

原因 是因为子级修改了父级的数据&#xff0c;所以eslint执行的时候报了这个错 修复方式 1 如果是弹窗等组件&#xff0c;可以根据功能进行修改&#xff0c;比如我这块用的 element ui 的 dialog&#xff0c;便可以改成这样 使用 model-value 代替 修复方式 2 新建子组件…

Java网络编程-Socket实现数据通信

文章目录 前言网络编程三要素IP地址和端口号传输协议Socket 使用Scoket实现网络通信TCPTCP通信-发送方TCP通信-接收方结果 UDPUDP通信-发送方UDP通信-接收方结果 总结 前言 本文主要是为下一篇Websockt做铺垫&#xff0c;大家了解socket的一些实现。 网络编程三要素 网络编程…

将符号分隔的文本文件txt转换为excel的实现

文本文件如下&#xff1a; 现在不好处理&#xff0c;打算将其转换为excel&#xff0c;其中通过冒号分割&#xff1a;line.split(":") main方法如下&#xff1a; public static void main(String[] args) {String textFilePath "D:\\zoom\\期刊\\J_Medline\\J_…

在Windows 10上部署ChatGLM2-6B:掌握信息时代的智能对话

在Windows 10上部署ChatGLM2-6B&#xff1a;掌握信息时代的智能对话 硬件环境ChatGLM2-6B的量化模型最低GPU配置说明准备工作ChatGLM2-6B安装部署ChatGLM2-6B运行模式解决问题总结 随着当代科技的快速发展&#xff0c;我们进入了一个数字化时代&#xff0c;其中信息以前所未有的…

大语言模型之七- Llama-2单GPU微调SFT

&#xff08;T4 16G&#xff09;模型预训练colab脚本在github主页面。详见Finetuning_LLama_2_0_on_Colab_with_1_GPU.ipynb 在上一篇博客提到两种改进预训练模型性能的方法Retrieval-Augmented Generation (RAG) 或者 finetuning。本篇博客过一下模型微调。 微调&#xff1a…

【大数据模型】让chatgpt为开发增速(开发专用提示词)

汝之观览&#xff0c;吾之幸也&#xff01;本文主要聊聊怎样才能更好的使用提示词&#xff0c;给开发提速&#xff0c;大大缩减我们的开发时间&#xff0c;比如在开发中使用生成表结构脚本的提示词&#xff0c;生成代码的提示词等等。 一、准备 本文主要根据Claude进行演示&am…

成集云 | 多维表格自动化管理jira Server项目 | 解决方案

源系统成集云目标系统 方案介绍 基于成集云集成平台&#xff0c;在多维表格中的需求任务信息自动创建、更新同步至 Jira Server 的指定项目中&#xff0c;实现多维表格中一表管理 Jira Server 中的项目进度。 维格表是一种新一代的团队数据协作和项目管理工具&…

hadoop学习:mapreduce入门案例四:partitioner 和 combiner

先简单介绍一下partitioner 和 combiner Partitioner类 用于在Map端对key进行分区 默认使用的是HashPartitioner 获取key的哈希值使用key的哈希值对Reduce任务数求模决定每条记录应该送到哪个Reducer处理自定义Partitioner 继承抽象类Partitioner&#xff0c;重写getPartiti…

C++算法 —— 动态规划(1)斐波那契数列模型

文章目录 1、动规思路简介2、第N个泰波那契数列3、三步问题4、使用最小花费爬楼梯5、解码方法6、动规分析总结 1、动规思路简介 动规的思路有五个步骤&#xff0c;且最好画图来理解细节&#xff0c;不要怕麻烦。当你开始画图&#xff0c;仔细阅读题时&#xff0c;学习中的沉浸…

简明易懂:Python中的分支与循环

文章目录 前言分支结构if 语句&#xff1a;单一条件判断else语句&#xff1a;提供备选方案elif 语句&#xff1a;多条件判断嵌套的分支结构&#xff1a;复杂条件逻辑 循环结构for循环&#xff1a;遍历序列range()函数与for循环while循环&#xff1a;条件重复循环控制&#xff1…

day-01 Docker

一、docker简介 Docker 是一种开源的容器化平台&#xff0c;它可以帮助开发人员将应用程序及其依赖项打包成一个独立的、可移植的容器&#xff0c;而无需担心环境差异和依赖问题。通过使用 Docker&#xff0c;您可以更轻松地创建、分发和运行应用程序&#xff0c;无论是在开发、…

Java后端开发面试题——多线程

创建线程的方式有哪些&#xff1f; 继承Thread类 public class MyThread extends Thread {Overridepublic void run() {System.out.println("MyThread...run...");}public static void main(String[] args) {// 创建MyThread对象MyThread t1 new MyThread() ;MyTh…

纽扣电池/锂电池UN38.3安全检测报告

根据规章要求&#xff0c;航空公司和机场货物收运部门应对锂电池进行运输文件审查&#xff0c;重要的是每种型号的锂电池UN38.3安全检测报告。该报告可由的三方检测机构。如不能提供此项检测报告&#xff0c;将禁止锂电池进行航空运输. UN38.3包含产品&#xff1a;1、 锂电池2…

JVM 访问对象的两种方式

Java 程序会通过栈上的 reference 数据来操作堆上的具体对象。由于 reference 类型在《Java 虚拟机规范》里面只规定了它是一个指向对象的引用&#xff0c;并没有定义这个引用应该通过什么方式去定位、访问到堆中对象的具体位置&#xff0c;所以对象访问方式也是由虚拟机实现而…