一步一步学习c#的设计模式与一个项目——第1部分

内容 在第1部分中我们将学习哪些模式和概念? 介绍 设计模式VS架构模式VS架构风格 设计模式的定义 酷店项目:-一期 软件架构是一种演进 什么是实体? 第一步:-识别你的实体/对象 步骤2:-确定实体之间的关系 步骤3:-从一个公共类派生 的技术背景 三层架构——管理变更 三层VS三层 步骤4:-创建用户界面 固体的S(单一责任原则) SRP同义词关注分离(SOC) 分离需要抽象思维——创建接口 步骤6:- PIC模式用于解耦(简单的工厂模式) 第7步:- RIP模式(用多态性替换IF) IOC有思想,DI有实现 所有在家庭:- SOC,SRP, IOC和DI 步骤8:-提高工厂类的性能 延迟加载工厂 家庭作业:-使用Lazy关键字自动加载懒惰 步骤10:-实现克隆(原型模式) 步骤11:-自动化简单的工厂使用Unity 第12步:-抽象类-半定义的东西 步骤13:-通用工厂 步骤14:-验证策略模式 消费并让它活起来 下一部分是什么? 在第1部分中我们将学习哪些模式和概念? RIP:-用多态替换IF。 简单工厂:-移动“新”关键字在中央类。 延迟加载:-按需加载对象。 原型模式:-创建一个对象的克隆。 策略模式:-动态添加算法。 IOC控制概念:-不必要的工作应该转移到其他地方。 依赖注入实现IOC。 坚实的原则:- SRP和OCP涵盖了坚实的原则。 介绍 在本文中,我们将学习如何使用c#语言实现设计模式和架构模式。我们不会一种模式一种模式地去做,而是拿一个示例项目,尝试在相同的基础上实现这些东西。 那么,为什么本文采用基于项目的方法,而不是基于实例的方法呢? 设计模式和架构模式是思维过程。思维过程无法用PPT、UML图表等来解释。您需要查看代码,您需要感受它,将它与真实的项目场景映射到一起。 如果你在互联网或书籍上看到大多数设计模式的文章都是用UML图(不是所有的开发人员都理解UML)或者像Car, Tree, Human’s等这样的例子来解释的,这些例子并不能让你觉得这些例子是真实的。 因此,让我们拿一个示例项目需求,让我们开始编码和设计一个应用程序,并让设计模式自然地沿着这个过程。 误解1:对于一个好的架构来说,所有的设计模式都必须在一个项目中实现。 事实:-模式自然产生,完全按需。 在你开始一些沉重的事情之前的一个小笑话 面试官:-告诉我你在现实生活中在哪里使用过设计模式。 应聘者:-只在面试的时候。 设计模式VS架构模式VS架构风格 误解2:设计模式和架构模式是相同的。 事实:设计模式至少在伪代码级别,而架构模式在组件级别。 单词“Pseudo”的意思:-大致看起来是这样的。 我们看到很多人交替使用这些词汇。但是它们的工作方式有很大的不同。 首先让我们试着理解“模式”这个词,然后我们再深入了解。 如果你明白pattern的简单英语含义:-它们是重复发生的和可预测的事件。 例如,气候变化遵循一种模式。一般来说(至少在印度是这样),夏天之后是下雨,然后是寒冷。人类识别这些模式,以更好的方式组织自己。 同样,在软件世界中,出现的问题大多有特定的模式,许多开发人员已经解决了这些问题并提出了解决方案。后来,其中一些解决方案在一段时间内证明了它们的价值,并成为该问题模式的标准解决方案。 例如,如果你想排序,那么你有时间测试的算法,如冒泡排序,插入排序等。 设计模式是伪代码级解决方案,而体系结构模式是在组件级定义的30,000英尺级解决方案。简单地说,如果有人说“X”是一种设计模式,那么就需要代码,如果有人说“Y”是一种架构模式,那么就需要某种组件级的框图。 建筑风格是一种思维过程,一种原则,它只出现在一行之内。例如,REST是一种我们重视HTTP的架构风格。 下面是他们各自的一些例子。 设计模式工厂,迭代器,单例架构模式mvc, MVP, mvvm架构风格rest, SOA, IOC 设计pattern定义 在我们继续项目之前,让我们试着给设计模式下一个定义,之后我们将定义体系结构模式。 如果你看到设计模式的官方定义,它是这样的:- “反复出现的架构问题的久经考验的解决方案”。 但是坦白地说,当您开始实现和阅读设计模式时,这个定义并不适用。有时你会发现设计模式完全是关于好的面向对象编程(OOP)原则。 所以让我根据我的理解和经验来定义我的定义。我可以保证,当我们开始运行所有的设计模式时,这个定义会更加清晰。 “针对反复出现的OOP问题的久经考验的解决方案”。 在这次访谈中,GOF团队自己也重复了这个定义。 误解3:设计模式让你成为一个完整的架构师。 事实:设计模式是一个建筑师的事情。它会让你的OOP更好。 实际上,设计模式只是让你在面向对象(OOP)方面变得更好,这是成为架构师的一个方面。但这并不是成为建筑师的唯一途径。我们也可以说设计模式是理解面向对象方案的一种方式。 因此,让我们不要浪费更多的时间,从一个典型的软件需求开始 酷店项目:-一期 “酷店”是一家大型零售购物中心,在孟买和浦那市拥有连锁购物中心。公司管理层希望为他们的零售商店提供一个简单的客户管理系统,具有以下功能。公司决定分阶段启动这个项目。 第一阶段,他们只想获取客户信息。以下是更详细的要求:- 应用程序现在将捕获5个字段:客户名称、电话号码、账单金额、账单日期和客户地址。在阶段1中收集了两种类型的客户数据。一个是引导者,另一个是顾客。lead指的是来到酷店却什么也不买的人。他只是问了问就走了。顾客就是来商店买东西的人。客户实际上是在进行金融交易。当它是一个领先的客户名称和电话号码是强制性的,但对于客户,所有字段都是强制性的。系统应该有无缝添加新验证规则的规定,这些验证规则应该是灵活的和可重用的,可以应用到系统中。系统应该能够显示,添加,更新和删除客户数据。目前系统将使用SQL Server和ADO。NET作为数据层技术。但在接下来的几个月里,我们将把这个数据层迁移到实体框架。迁移应该是无缝的,不需要跨系统进行很多更改。系统应该有能力取消在屏幕上做的任何修改。因此,如果客户正在编辑一条记录,并且更改了一些值,那么他应该有机会恢复到旧值。 软件架构是一种演进 误解4:-架构应该在第一时间就完美无误。 事实:——建筑是一种进化。从小处开始,然后不断改进。 对于新架构师来说,这是他们最大的信条之一。软件架构会自然地演进,模式也会在这个过程中逐渐衰落,最终形成最终的结果。 许多人试图通过一个接一个的代码和一个接一个的模式来学习设计和架构模式。这种学习模式是非常有害的,因为你只是看到一些学术代码,但它永远不会成为你自然的一部分。 学习设计模式的最佳方法是通过做一个项目来观察整个演变过程,然后让模式在整个过程中自然地逐渐消失。 因此,我们不会学习一个接一个的模式,我们只会尝试构建上面的项目,随着模式的出现,我们会自然而然地指出模式。 因此,让我们首先从简单的OOP概念、类、对象和随需而来的模式开始。 什么是实体? 我们需要做的第一件事是识别实体。让我们来理解实体在英语中的确切含义。 实体是你在现实世界中看到的事物。这些可以唯一地标识。例如,一个人,地点,事物等等都是实体的例子。 在OOP世界中,实体的技术名称是对象。所以我们在这篇文章中可以互换使用这两个词。 第一步:-识别你的实体/对象 思维过程1:-软件代码应该复制真实的世界,真实的人。如果你是一个会计在你的软件代码中,你应该有一个叫做会计的实体。 软件应用程序的创建是为了使真实世界和真实的人自动化。因此,如果你的软件代码复制了现实世界的对象,你可以管理你的软件在一个更好的和可控的方式。 这就是面向对象编程的全部内容。OOP说你的鳕鱼e应该反映你的域行为和域的实体。 域是指业务单元,其规则和它是如何工作的。 所以第一步是识别实体/对象从上面的要求。所以从顶部下面的要求确定名词:- 孟买浦那客户带来凉爽的商店 思维过程2:名词成为实体和动词成为实体的行为。代词成为这些实体的属性和行为。 许多建筑师遵循实践之一是识别名词、代词和动词。这些名词然后分析和确定为对象/实体。但是要小心使用此方法,因为你可以得到多余的名词和动词。所以只保留那些名词和动词与最终的软件系统。 如果你回顾上述识别实体现在“孟买”和“普”是城市的名字和与软件没有直接联系。“CoolShop”,这是商场的名称也没有直接联系。 所以此刻唯一有用的实体在阶段1是“领导”和“客户”。我们将添加、更新、删除数据的客户。 现在这样的实体来住在你的电脑,你需要的代码和逻辑。所以我们需要某种形式的一个模板,我们可以编写这段代码中,这就是我们术语“类”。这个类将thenbe实例化创建对象和实体在你的电脑。 OOP过程分为三个阶段:- 模板创建:创建类和编写逻辑的类。这些类的实例化:创建实体/对象并将他们住在RAM /电脑。运行:与这些对象来实现软件功能。 现在作为一名开发人员你会遇到常见/重复designproblems在所有这三个阶段。OOP设计模式解决方案问题在所有这三个阶段。设计模式分为三类,它们覆盖这些阶段如下:- OOP阶段设计模式类别模板结构设计模式/类的创建问题。创建型设计模式实例化问题。运行时行为设计模式的问题。 让我们创建两个类一个是领导,另一个是客户。 下面是对于两个类的代码。 注意:——我从这里可以看到人表里不一的担忧我的下面的代码。不久我将解决他们,继续读。 隐藏,复制Code

namespace CustomerLibrary
{
public class Lead
    {
        public string LeadName { get; set; }
        public string PhoneNumber { get; set; }
        public string PhoneNumber { get; set; }
        public decimal BillAmount { get; set; }
        public DateTime BillDate { get; set; }
        public string Address { get; set; }
    }
    public class Customer
    {
        public string CustomerName { get; set; }
        public string PhoneNumber { get; set; }
        public decimal BillAmount { get; set; }
        public DateTime BillDate { get; set; }
        public string Address { get; set; }
    }
}

步骤2:确定实体之间的关系 现实世界中实体相互作用,他们之间的关系。我们的下一步是确定实体之间的关系。如果你想象的关系,存在于现实世界中,他们是主要的两种类型“是一个”和“有”。 例如儿子”是一个“孩子他父亲和儿子”有一个“汽车的他的父亲。”是一个“更多的是父母的孩子的关系(层次),而“有”更多的是一种利用关系(聚合、组合和相关)。 如果你读的要求第二,这显然意味着:- “铅是一种类型的客户用更少的验证”。 现在我们班变成了如下所示的代码。“领导”是一个子类继承了从“客户”类。 隐藏,复制Code

public class Customer
{
        public string CustomerName { get; set; }
        public string PhoneNumber { get; set; }
        public decimal BillAmount { get; set; }
        public DateTime BillDate { get; set; }
        public string Address { get; set; }
}
public class Lead : Customer
{

}

“客户”实体客户的名字,电话号码,金额和账单日期是强制性的。以下代码中,我们创建了一个简单的“验证”方法检查上面的所有属性。 最重要的一点是,“验证”方法是由虚拟。这新类可以覆盖验证逻辑。 隐藏,复制Code

public class Customer
    {
// All properties are deleted for simplification
        public virtual void Validate()
        {
            if (CustomerName.Length == 0)
            {
                throw new Exception("Customer Name is required");
            }
            if (PhoneNumber.Length == 0)
            {
                throw new Exception("Phone number is required");
            }
            if (BillAmount > 0)
            {
                throw new Exception("Bill is required");
            }
            if (BillDate >= DateTime.Now)
            {
                throw new Exception("Bill date  is not proper");
            }
        }
    }

下一步是创建一个“领导”类继承自“客户”类和覆盖验证方法。讨论了“铅”类将限制较少,因为它只需要姓名和电话号码。下面是代码覆盖客户类少验证。 隐藏,复制Code

public class Lead : Customer
    {
        public override void Validate()
        {
            if (CustomerName.Length == 0)
            {
                throw new Exception("Customer Name is required");
            }
            if (PhoneNumber.Length == 0)
            {
                throw new Exception("Phone number is required");
            }
        }}

思维过程3:——“是一个”的关系是一个家长孩子的关系,而“有”是一个使用关系。 步骤3:源于一个共同的阶级 如果你读要求4号表示,系统应该能够添加新的客户类型的明天。 按这个要求我们班设计看起来不符合逻辑的。一个逻辑的方法是,应该有一个定义的“一半”类与所有属性和“验证”方法应该是空的(半)定义的。这个空的方法可以被子类覆盖取决于他们的行为。 换句话说,我们应该有某种的基类我们可以得到客户和领导阶级。 下面是客户基础类和所有属性和“验证”方法保持空定义它的子类。 隐藏,复制Code

public class CustomerBase
{
        public string CustomerName { get; set; }
        public string PhoneNumber { get; set; }
        public decimal BillAmount { get; set; }
        public DateTime BillDate { get; set; }
        public string Address { get; set; }
        public virtual void Validate()
        {
         // Let this be define by the child classes 
        }
}

注意:——一些高级的人读这篇文章已经尖叫,使这类“抽象”。是的,很快。我想推迟进一步ca理解抽象类的实时使用。 因此,现在如果我们想创建一个customer类,我们只需从基customer类继承并放入验证即可。 隐藏,复制Code

public class Customer : CustomerBase
    {
        public override void Validate()
        {
            if (CustomerName.Length == 0)
            {
                throw new Exception("Customer Name is required");
            }
            if (PhoneNumber.Length == 0)
            {
                throw new Exception("Phone number is required");
            }
            if (BillAmount > 0)
            {
                throw new Exception("Bill is required");
            }
            if (BillDate >= DateTime.Now)
            {
                throw new Exception("Bill date  is not proper");
            }
        }
    }

如果我们想创建一个只验证姓名和电话号码的Lead类,我们可以再次从“CustomerBase”类继承并相应地编写验证。 隐藏,复制Code

public class Lead : CustomerBase
    {
        public override void Validate()
        {
            if (CustomerName.Length == 0)
            {
                throw new Exception("Customer Name is required");
            }
            if (PhoneNumber.Length == 0)
            {
                throw new Exception("Phone number is required");
            }
        }
    }

的技术背景 以上定义的三个类都以“的形式存储在硬盘中。CS”扩展。现在需要做两件事:- 一些UI应该调用这些类,把这些实体放到RAM中。第二,一旦最终用户完成了他的操作,我们需要将这些实体存储到硬盘中。 换句话说,我们的实体需要IT基础设施来运行。它需要一个UI基础设施(WPF、Flash、HTML)用于调用,需要一个持久化基础设施(Sql Server、Oracle)用于保存到硬盘。 如果你把这些情况的可视图片和技术背景放在一起,它看起来就像这样。所以我们可以有消费者上下文,可以是HTML, WPF, Windows等形式。我们可以有持久的上下文,它可以是一个文件或RDBMS,如SQL Server, Oracle等。 有了以上的想法,我们以三种类型的部分结束:- 消费者部分,主要是UI。包含类和业务逻辑的域部分。持久部分,除了你的RDBMS,文件等。 思维过程4:-当你想象一个类总是他们在这两个技术上下文和业务实体上下文。 三层架构——管理变更 软件架构的试金石测试是在变更期间进行的。当你在一个地方改变,如果你在很多地方改变,这意味着这是一个糟糕的架构的标志。 因此,为了避免在所有地方都发生变化,我们需要做出适当的分层和划分,并在这些分层上放上类似性质的责任。因此,正如在技术上下文中所讨论的,我们目前至少有三个部分,UI、领域/业务层和数据层。 在同一个项目中,我们为UI部分添加一个简单的Windows UI。 我们需要类库一个用于“数据访问”,另一个用于客户实体。 所以现在你的解决方案看起来如下图所示。三种不同的项目层次。 那么,分层是如何帮助我们更好地管理变化的呢?因为我们已经将项目划分为逻辑层,所以很容易知道在哪个层中必须进行哪些更改。例如,如果我们想升级数据访问层,我们只需要改变第三层,如果我们想从一种UI技术转移到另一种,我们需要改变UI层,等等。 上述架构称为“三层架构”。 思维过程5:-总是把你的项目分成逻辑层次,每一层次都应该有一些独特的责任。 三层VS三层 架构世界中一个令人困惑的术语是“层”架构与“层”架构。在三层架构中,我们只有逻辑分离。在三层中,所有这三个层都部署在独立的物理机器上。 步骤4:-创建用户界面 在UI层中,我们为UI放置了必要的控件。 在这个UI层中,我们添加了对“Customer”库的引用,在下拉菜单中,我们创建了一个“Lead”对象或“Customer”对象。 隐藏,复制Code

private void btnAdd_Click(object sender, EventArgs e)
{
            CustomerBase custbase = null;
            if (cmbCustomerType.SelectedIndex == 0)
            {
                custbase = new Lead();
            }
            else
            {
                custbase = new Customer();
            }
            custbase.CustomerName = txtCustomerName.Text;
            custbase.Address = txtAddress.Text;
            custbase.PhoneNumber = txtPhoneNumber.Text;
            custbase.BillDate = Convert.ToDateTime(txtBillingDate.Text);
            custbase.BillAmount = Convert.ToDecimal(txtBillingAmount.Text);
}

所以你能猜到上面的代码有什么问题吗?想? ?。 好的,我们在下面圈出了这个问题来帮助你理解这个问题。问题是“改变”。正如在需求4中定义的那样,未来可以添加新的客户类型。因此,当添加新的客户类型时,我们需要更改UI代码,或者让我来推断许多这样的UI屏幕。 记住我们说过的,一个好的架构是这样的架构当我们在一个地方改变时,我们不需要在所有地方都改变。 固体的S(单一责任原则) 是时候谈谈坚实的原则了。如果我们遵循这些原则,我们的OOP就会更好。 单一责任原则(SRP)。开闭原则(OCP)利斯科夫替代原则(LSP)接口分离原则(ISP)依赖反演原则。 现在让我们不要谈论所有的SOLID原则,如果你想现在就了解它,你可以阅读这篇c# SOLID文章,它只讨论SOLID原则。 现在让我们只集中在坚实的“S”,即单一责任原则(SRP)。 SRP说一个类应该一次只做一个工作,而不是不相关的事情。如果你看到UI,它应该做布局,视觉,输入等等。但现在他正在创建一个“客户”对象,这不是他的职责。 换句话说,UI正在处理多种职责,这使得类在以后变得更加复杂和难以维护。 思考过程6:坚持坚定的原则当你在做设计。 SRP同义词的关注点分离(SOC) 的一个同义词SRP SOC -分离的问题。分离关注点原则说,一个类应该只有他的担忧和任何不必要的担忧应该搬到其他类。例如在这种情况下,界面不应该直接创建“客户”对象。 所以下次当你看到SOC你可以认为这是一个同义词SRP反之亦然。 注意:——我不知道先SOC还是SRP的历史。但他们肯定有相同的目标。 第五步:创建接口——分离需要抽象思维 为了实现解耦的UI和客户类型,用户界面必须看到客户类型在一种抽象的方式而不是处理具体类。 抽象:这是一个OOP原则,我们只显示消费者必要的事情。 UI应该只与纯粹的定义而不是具体类实现。这就是接口来的照片。帮助你创建纯定义接口。UI将指出这些纯粹的定义,而不是担心在后台实现类。 让我们创建一个单独的类库使用一个名称“ICustomerInterface”相同的解决方案。这个接口我们将参考在UI中。下面是接口如何“ICustomer”的样子,只是空定义和空方法。 隐藏,复制Code

public interface ICustomer
{
         string CustomerName { get; set; }
         string PhoneNumber { get; set; }
         decimal BillAmount { get; set; }
         DateTime BillDate { get; set; }
         string Address { get; set; }
         void Validate();

}

现在整个解决方案从架构的角度看起来如下所示。现在的接口之间的调停人UI和客户类库。 所以,如果你现在看到它变成了我们的客户代码如下所示。 隐藏,复制Code

ICustomer icust = null;
if (cmbCustomerType.SelectedIndex == 0)
{
icust = new Lead();
}
else
{
icust = new Customer();
}
icust.CustomerName = txtCustomerName.Text;
icust.Address = txtAddress.Text;
icust.PhoneNumber = txtPhoneNumber.Text;
icust.BillDate = Convert.ToDateTime(txtBillingDate.Text);
icust.BillAmount = Convert.ToDecimal(txtBillingAmount.Text);

但实际上事情并没有改变。如果我们添加一个新的类我们仍然需要创建具体实现类的对象。 所以我们需要更多的东西,看下一步的解决方案。 思维过程7:接口的主要工作是互相分离的类。 步骤6:图片模式解耦(简单工厂模式) 图片的缩略词是“多态性+接口+集中对象创建” 如果你密切关注代码的你会得到的核心原因仍然不是脱钩。因为所有的“新”字。“新”字两个系统的主要原因之一是紧密耦合的。 所以第一步是摆脱“新”字从消费者端。让我们开始的“新”字中央工厂类。 所以我们增加了一个新的类库项目称为“FactoryCustomer”下面的代码。 隐藏,复制Code

public class Factory
{
        public ICustomer Create(int CustomerType)
        {
            if (CustomerType == 0)
            {
                return new Lead();
            }
            else
            {
                return new Customer();
            }
        }
}

它有一个简单的“工厂”类的创建方法。这种“创造”方法接受一个数字值,根据数值创建一个“领导”对象或一个“客户”对象。但这种“创造”的专业函数,它返回“ICustomer”接口类型。 现在控制台应用程序UI使用创建对象的“工厂”,因为“创造”函数返回“ICustomer”类型的UI并不需要担心具体客户类的后端。 隐藏,复制Code

ICustomer icust = null;
Factory obj = new Factory();
icust = obj.Create(cmbCustomerType.SelectedIndex);

在上面的代码中可以看到没有参考具体类的“领导”或“客户”类型,显示UI不是与核心客户库类。 如果你想知道为什么我们叫类“工厂”。在现实世界中意味着创造(制造)事物的一个实体,我们的“工厂”类正是这样创建对象。所以名字同样有着密切联系。 思维过程8:——“新”字是紧密耦合的罪魁祸首。 第七步:把模式(如果换成多态性) 如果你看步骤6的代码我们刚刚通过了美元。“如果”条件是在UI中部分是现在工厂哪个更好的一部分,但在现实中,“如果”条件仍然存在。只是它一直从UI搬到工厂。 集中对象创建的优势是,如果我们在很多地方使用具体类和客户在其他地方我们不需要改变。 现在让我们开始思考我们如何消除“如果”条件。你一定听说过以下最佳实践声明:- “如果有多态性,这意味着如果你看到很多条件多态的好处不是剥削”。 删除“如果”条件过程分为三个步骤:- 步骤1:创建一个列表“ICustomer”的集合。 隐藏,复制Code

private List<icustomer> customers = new List<icustomer>();</icustomer></icustomer>

步骤2:在构造函数中加载类型的客户类像铅和客户。 隐藏,复制Code

public Factory()
        {
            customers.Add(new Lead());
            customers.Add(new Customer());
        }

步骤3:创建方法看看通过索引列表,返回类型的客户。因为多态性的具体客户类会自动类型(一个通用的接口。 隐藏,复制Code

public ICustomer Create(int CustomerType)
        {
            return customers[CustomerType];
        }

下面是更改的工厂类的完整代码。 隐藏&,复制Code

public class Factory
{
        private List<icustomer> customers = new List<icustomer>();
        public Factory()
        {
            customers.Add(new Lead());
            customers.Add(new Customer());
        }
        public ICustomer Create(int CustomerType)
        {
            return customers[CustomerType];
        }
}
</icustomer></icustomer>

注意:——把最大的约束模式,具体类应该在继承层次结构和具有相同的签名。多态和继承是一个强制性的特性把模式存在。 思维过程9:-在多态如果可以换成动态多态集合。 模式1把模式:如果你有多态性的优势,你会看到大量的IF条件,有很好的机会,你可以用一个简单的替换,如果条件查找集合。这种模式行为范畴。 国际奥委会认为,DI实现 国际奥委会是一个思想或者说我可以说实体的原则无关的工作应该搬出去的地方。再次读到完整形式:控制反转或者我们可以非常具体的说UNWANTEDcontrol其他实体的反演。 如果你看到在上面的场景中,我们移动或我将说我们倒“客户”的不必要的责任对象创建UI的“工厂”类。 现在国际奥委会原则可以通过多种方式来实现,依赖注入,代表等等。 为了实现这一思维过程我们使用了“工厂”类。如果你看到从工厂类的角度来看我们注入一个对象的UI。所以UI需要注入的工厂类的对象。迪是一个注入依赖对象的过程从一个单独的实体来实现解耦。 所有的家庭:- SOC, SRP,国际奥委会和DI 如果你看到密切SOC, SRP和奥委会几乎是同义词和这些原则可以实现通过使用DI,事件,代表,构造函数注入,服务定位器等。所以对我来说SOC, SRP和奥委会看起来都同义词。 我鼓励你看这个视频解释了国际奥委会和DI几乎。 第八步:提高性能的工厂类 在上面的建筑工厂类将执行很差如果我们有很多具体的对象 明天如果我们一次又一次地创建工厂实例将导致大量的内存消耗。 所以如果我们能有一个与所有具体工厂类的实例对象加载一次,真的会提高性能。这一实例可以用于满足所有客户的需求实例。 为了单一实例复制我们需要做以下:- 声明为静态的类。声明的类型列表将被存储为静态的。最后创建函数也应该定义静态,这样它可以访问静态变量。 隐藏,复制Code

public static class Factory
    {
        private static List<icustomer> customers = new List<icustomer>();
        static Factory()
        {
            customers.Add(new Lead());
            customers.Add(new Customer());
        }
        public static ICustomer Create(int CustomerType)
        {
            return customers[CustomerType];
        }
    }
</icustomer></icustomer>

工厂在客户端调用代码变得简单得多了。 隐藏,复制Code

icust = Factory.Create(cmbCustomerType.SelectedIndex);

模式2简单工厂模式:通过集中对象创建和返回一个通用接口参考,有助于减少变化时变化应用于应用程序。这瀑布在创建类别。 这种模式不应被混淆与四人帮的工厂模式。工厂模式是简单工厂模式的基础。 步骤9:-延迟加载的工厂 还其他伟大的事情我们可以做这里的工厂是按需加载对象。如果你看到现在的对象加载不管你希望他们。我们只是加载即时,换句话说,当我们想要的对象我们加载它们。 所以延迟加载转换上面的工厂是一个两步过程:- 步骤1:使对象集合类型空。不加载它们。 隐藏,复制Code

private static List<icustomer> customers = null;</icustomer>

步骤2:创建函数将首先检查对象是否为空然后加载它,否则只是集合中查找。 隐藏,复制Code

public static ICustomer Create(int CustomerType)
        {
            if (customers == null)
            {
                LoadCustomers();
            }
            return customers[CustomerType];
        }

下面是延迟加载的完整代码。 隐藏,复制Code

public static class Factory
{
        private static List<icustomer> customers = null;

        private static void LoadCustomers()
        {
            customers = new List<icustomer>();
            customers.Add(new Lead());
            customers.Add(new Customer());
        }
        public static ICustomer Create(int CustomerType)
        {
            if (customers == null)
            {
                LoadCustomers();
            }
            return customers[CustomerType];
        }
}
</icustomer></icustomer>

模式3延迟加载:这是我们加载对象创建型设计模式,只有当我们需要它。延迟加载的反面是立即加载。 家庭作业:自动化使用懒字延迟加载 懒惰的设计模式可以自动化,使简单的通过使用c#懒惰的关键字。我将作为你们的家庭作业。看到下面的youtube视频理解c#延迟加载概念,然后尝试您的自定义代码替换为c#懒惰的关键字。 下面是使用c#编写的代码懒惰的关键字。 隐藏,复制Code

public static class Factory
    {
        private static Lazy<list<icustomer>> customers = null;
        public Factory()
        {
            customers = new Lazy<list<icustomer>>(() => LoadCustomers());
        }
        private  List<icustomer> LoadCustomers()
        {
            List<icustomer> custs = new List<icustomer>();
            custs.Add(new Lead());
            custs.Add(new Customer());
            return custs;
        }
        public static ICustomer Create(int CustomerType)
        {
            return customers.Value[CustomerType];
        }
    }
</icustomer></icustomer></icustomer></list<icustomer></list<icustomer>

第十步:实现克隆(原型模式) 现在上面的工厂模式类有一个缺陷,你能猜出这是什么吗?。 隐藏,复制Code

icust = Factory.Create(0);

现在为什么会返回相同的实例,因为工厂模式是指向相同的实例的集合。这是灾难性的,因为工厂的目的是创建新实例,而不是返回相同的实例。 所以我们需要某种机制,而不是返回相同的对象应该返回一个克隆的对象,一个由VAL副本。这就是原型模式图片。 所以第一步是定义一个“ICustomer”界面中的“克隆”方法。 隐藏,复制Code

public interface ICustomer
{
         string CustomerName { get; set; }
         string PhoneNumber { get; set; }
         decimal BillAmount { get; set; }
         DateTime BillDate { get; set; }
         string Address { get; set; }
         void Validate();
         ICustomer Clone(); // Added an extra method clone
}

为了创建一个. net对象的“克隆”我们有现成的“MemberwiseClone”功能。基类的客户我们有相同的实现。这种方法的任何其他类型的客户类是继承也将克隆对象的能力。 隐藏,复制Code

public class CustomerBase : ICustomer
{
// Other codes removed for readability       
public ICustomer Clone()
{
            return (ICustomer) this.MemberwiseClone();
}
}

现在工厂的“创建”功能将调用克隆方法后,从集合中查找。所以同一个引用的对象不会被发送,这将是一个新的对象的副本。 隐藏,复制Code

public static class Factory
{
// Other codes are removed for readability purpose
public static ICustomer Create(int CustomerType)
{
return customers.Value[CustomerType].Clone();
}
}

模式4原型模式:这是一个创建型设计模式,我们创建一个新的克隆/一个对象的实例。 步骤11:-自动化简单工厂使用统一 一个好的开发人员总是狩猎如何由现成的自动化设计模式框架。例如上面的简单工厂类是伟大的但现在想一想如果我们需要支持其他对象类型,如订单,记录器等等。所以写工厂对于每个其中之一,创建多态集合,然后在上面查测试所有这些事情本身是一项艰巨的任务。 完成简单的工厂和多态收集查找可以使用一些自动化/取代了DI框架统一,ninject, MEF等等。 我能理解一些人喊出“迪是什么?”。屏住呼吸很快我们将讨论。现在让我们专注于如何简单的工厂可以自动使用DI框架。现在,我们将选择统一应用程序块。 所以第一步是得到统一使用NUGET应用程序块在你的工厂类。如果你是NUGET你可以看到这个视频,NUGET基本面解释道。 所以第一步是让持有统一名称空间的应用程序块。 隐藏,复制Code

using Microsoft.Practices.Unity;

在统一或任何DI框架容器的概念。这些容器集合。“RegisterType”和“ResolveType”方法有助于分别添加和得到对象从容器中收集。 隐藏,复制Code

static  IUnityContainer cont = null;
        static Factory()
        {
            cont = new UnityContainer();
            cont.RegisterType<icustomer,lead="">("0");
            cont.RegisterType<icustomer,customer="">("1");
        }
        public static ICustomer Create(int CustomerType)
        {
            return cont.Resolve<icustomer>(CustomerType.ToString());
        }
</icustomer></icustomer,></icustomer,>

下面的图片显示了如何手动工厂模式代码映射到自动统一容器的代码。 步骤12:-抽象类定义的一半 如果你还记得“CustomerBase”类这是一半定义类。它定义了所有属性但后来验证方法定义的孩子具体类。现在想一想如果有人创建了这一半的对象定义类,可以什么后果?。 会发生什么如果他调用下面空的“验证”方法?。 是的,你猜对的混乱。 隐藏,复制Code

public class CustomerBase : ICustomer
{
        public string CustomerName { get; set; }
        public string PhoneNumber { get; set; }
        public decimal BillAmount { get; set; }
        public DateTime BillDate { get; set; }
        public string Address { get; set; }
        public void Validate()
	  {
		// To be defined by the child classes
  }
}

所以解决办法是避免混乱不允许客户端创建对象的类定义的一半即creatingan“抽象类”。 隐藏,复制Code

public abstract class CustomerBase : ICustomer
{
        public string CustomerName { get; set; }
        public string PhoneNumber { get; set; }
        public decimal BillAmount { get; set; }
        public DateTime BillDate { get; set; }
        public string Address { get; set; }
        public abstract void Validate();
}

现在如果客户机试图创建抽象类的对象,他将与以下错误抛出,这有助于我们防止混淆使用一半的类定义。 步骤13:-通用的工厂 如果你看到工厂类与“客户”的绑定类型。换句话说,如果我们想下班打卡“供应商”类型,我们需要一个更“创造”的方法如以下代码所示。如果我们有很多业务对象这样我们会得到很多的“创造”的方法。 隐藏,复制Code

public static class Factory
{
public static ICustomer Create(int CustomerType)
{
return cont.Resolve<icustomer>(CustomerType.ToString());
}
public static Supplier Create(int Supplier)
{
return cont.Resolve<isupplier>(Supplier.ToString());
}
}
</isupplier></icustomer>

与其绑定单个类型的“工厂”如何成为一个“通用的”类。 如果你是“仿制药”我建议你通过这个youtube c#泛型视频解释了细节的方式“仿制药”的概念。并且如果你从学校认为“一般”和“通用”集合一样你应该看到上面的视频删除,误解。 通用帮助你解耦的逻辑数据类型。这里的逻辑是“对象创建”,但将这种逻辑只与“客户”会使体系结构刚性。所以如何使它成为泛型类型“AnyType”如以下代码所示。 隐藏,复制Code

public static class Factory<anytype>
{
static IUnityContainer container = null;
public static AnyType Create(string Type)
{
if (container == null)
            {
                container = new UnityContainer();
                container.RegisterType<icustomer,lead="">("Lead");
                container.RegisterType<icustomer,customer="">("Customer");
            }
return container.Resolve<anytype>(Type.ToString());
}
}
</anytype></icustomer,></icustomer,></anytype>

注意:——我已经改变的关键从数字“0”和“1”到“领导”和“客户”,使其更具可读性。 所以现在当客户想要创建“客户”对象他需要调用如下所示。 隐藏,复制Code

ICustomer Icust =  Factory<icustomer>.Create("Customer");</icustomer>

步骤14:-策略模式进行验证 如果你读要求3号它说验证“客户”是不同的,不同的“领导”。“客户”“领导”的所有字段是强制性的,只足够多的姓名和电话号码。 为了达到相同的我们已经创建了一个虚拟“验证”方法,该方法分别与新规则覆盖新类。 隐藏,收缩,复制Code

public class Customer : CustomerBase
    {
public override void Validate()
        {
if (CustomerName.Length == 0)
            {
throw new Exception("Customer Name is required");
            }
if (PhoneNumber.Length == 0)
            {
throw new Exception("Phone number is required");
            }
if (BillAmount == 0)
            {
throw new Exception("Bill Amount is required");
            }
if (BillDate >= DateTime.Now)
            {
throw new Exception("Bill date  is not proper");
            }
        }
    }

public class Lead : CustomerBase
    {
public override void Validate()
        {
if (CustomerName.Length == 0)
            {
throw new Exception("Customer Name is required");
            }
if (PhoneNumber.Length == 0)
            {
throw new Exception("Phone number is required");
            }
        }
    }

但如果你读的要求又进一步说,这有可能增加新的验证,我们预计系统灵活或我将r皮革、皮革制品说动态实现相同的。 但当我们使用继承其静态与动态。第二个“客户”类和“铅”类与验证算法/策略是紧耦合的。所以如果我们想achievedynamic灵活性我们需要删除这个验证逻辑实体和其他地方。 此刻的实体类与验证算法。简而言之: 我们不是SRP之后。我们没有做SOC所以我们需要实现国际奥委会,这意味着我们需要将算法的逻辑从实体类,其他类。 现在为了实现解耦之间的“实体”和“验证逻辑”我们需要确保这两个政党通过一个通用接口而不是直接对话的具体类。 我们已经有一个通用接口“客户”以同样的方式让我们创建一个通用接口验证算法,我们将术语“IValidationStratergy”这个接口。我们还要注意接口通用,这样我们可以使用这个接口明天等其他类型的“供应商”,“账户”等。 隐藏,复制Code

public interface IValidationStratergy<anytype>
{
void Validate(AnyType obj);
}
</anytype>

现在我们可以进一步实现上面的接口和创建不同的validationlogics。例如下面的验证检查 隐藏,复制Code

public class CustomerAllValidation  : IValidationStratergy<icustomer>
    {

public void Validate(ICustomer obj)
        {
if (obj.CustomerName.Length == 0)
            {
throw new Exception("Customer Name is required");
            }
if (obj.PhoneNumber.Length == 0)
            {
throw new Exception("Phone number is required");
            }
if (obj.BillAmount == 0)
            {
throw new Exception("Bill Amount is required");
            }
if (obj.BillDate >= DateTime.Now)
            {
throw new Exception("Bill date  is not proper");
            }
        }
    }
</icustomer>

隐藏,复制Code

public class LeadValidation : IValidationStratergy<icustomer>
    {
public void Validate(ICustomer obj)
        {
if (obj.CustomerName.Length == 0)
            {
throw new Exception("Customer Name is required");
            }
if (obj.PhoneNumber.Length == 0)
            {
throw new Exception("Phone number is required");
            }
        }
    }
</icustomer>

现在基类将内部一般验证接口。现在,“客户”和“领导”类不知道他会执行什么样的验证策略。 隐藏,复制Code

public abstract class CustomerBase : BoBase, ICustomer
{
// Code removed for simplification
private IValidationStratergy<icustomer> _ValidationType = null;
public CustomerBase(IValidationStratergy<icustomer> _Validate)
{
            _ValidationType = _Validate;
}
public IValidationStratergy<icustomer> ValidationType
{
get
            {
return _ValidationType;
            }
set
            {
                _ValidationType = value;
            }
        }
}
}
</icustomer></icustomer></icustomer>

现在在工厂类,我们可以创建任何实体和注入任何验证。你可以看到我们已经创建了一个客户类和injectedthe所有验证类对象。以同样的方式我们已经创建了一个领导类和注射导致验证对象。 隐藏,复制Code

container.RegisterType<icustomer,customer="">("Customer", new InjectionConstructor(newCustomerAllValidation()));

container.RegisterType<icustomer,lead="">("Lead", new InjectionConstructor(new LeadValidation()));
</icustomer,></icustomer,>

下面是工厂的完整代码。 隐藏,复制Code

public static class Factory<anytype>
{
static IUnityContainer container = null;

public static AnyType Create(string Type)
        {
if (container == null)
            {
                container = new UnityContainer();
                container.RegisterType<icustomer,customer="">("Customer", 
                                new InjectionConstructor(newCustomerAllValidation()));
                container.RegisterType<icustomer,lead="">("Lead", 
                                    new InjectionConstructor(new LeadValidation()));

            }
return container.Resolve<anytype>(Type.ToString());
        }

    }
</anytype></icustomer,></icustomer,></anytype>

模式5策略模式:这是一个行为设计模式有助于在运行时选择算法。 消费和生活 如果你还记得我们已经有了一个UI所以我刚刚消耗的更新UI。 下面是按钮验证事件的代码。 隐藏,复制Code

// Create customer or lead type depending on the value of combo box
icust = Factory<icustomer>.Create(cmbCustomerType.Text);

// Set all values
icust.CustomerName = txtCustomerName.Text;
icust.Address = txtAddress.Text;
icust.PhoneNumber = txtPhoneNumber.Text;
icust.BillDate = Convert.ToDateTime(txtBillingDate.Text);
icust.BillAmount = Convert.ToDecimal(txtBillingAmount.Text);


// Call validate method
icust.Validate();
</icustomer>

在接下来的部分是什么? 在接下来的部分,我们将涵盖以下五个模式:- 创建DAL层使用ADO。净和分离他们使用存储库模式,UOW和适配器模式。在ADO使用模板模式。NET代码重用命令和连接对象。使用Facade模式简化UI代码。 下面是一个很好的设计模式youtube视频一步一步这解释了如何使用设计模式在c#项目。 本文转载于:http://www.diyabc.com/frontweb/news2167.html

posted @ 2020-08-08 12:25  Dincat  阅读(340)  评论(0编辑  收藏  举报