.NET设计模式(7):创建型模式专题总结(Creational Pattern)

概述

创建型模式,就是用来创建对象的模式,抽象了实例化的过程。它帮助一个系统独立于如何创建、组合和表示它的那些对象。本文对五种常用创建型模式进行了比较,通过一个游戏开发场景的例子来说该如何使用创建型模式。

为什么需要创建型模式

所有的创建型模式都有两个永恒的主旋律:第一,它们都将系统使用哪些具体类的信息封装起来;第二,它们隐藏了这些类的实例是如何被创建和组织的。外界对于这些对象只知道它们共同的接口,而不清楚其具体的实现细节。正因如此,创建型模式在创建什么(what),由谁(who)来创建,以及何时(when)创建这些方面,都为软件设计者提供了尽可能大的灵活性。

假定在一个游戏开发场景中,会用到一个现代风格房屋的对象,按照我们的一般想法,既然需要对象就创建一个:

ModernRoom room = new ModernRoom();

好了,现在现代风格房屋的对象已经有了,如果这时房屋的风格变化了,需要的是古典风格的房屋,修改一下:

ClassicalRoom room = new ClassicalRoom();

试想一下,在我们的程序中有多少处地方用到了这样的创建逻辑,而这里仅仅是房屋的风格变化了,就需要修改程序中所有的这样的语句。现在我们封装对象创建的逻辑,把对象的创建放在一个工厂方法中:

ModernFactory factory = new ModernFactory();

ModernRoom room = factory.Create();

当房屋的风格变化时,只需要修改

ClassicalFactory factory = new ClassicalFactory();

ClassicalRoom room = factory.Create();

而其它的用到room的地方仍然不变。这就是为什么需要创建型模式了。创建者模式作用可以概括为如下两点:

1.封装创建逻辑,绝不仅仅是new一个对象那么简单。

2.封装创建逻辑变化,客户代码尽量不修改,或尽量少修改。

常见的五种创建型模式

单件模式Singleton Pattern)解决的是实体对象的个数问题,其他的都是解决new所带来的耦合关系问题。

工厂方法模式Factory Pattern)在工厂方法中,工厂类成为了抽象类,其实际的创建工作将由其具体子类来完成。工厂方法的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中去,强调的是“单个对象”的变化。

抽象工厂模式Abstract Factory)抽象工厂是所有工厂模式中最为抽象和最具有一般性的一种形态。抽象工厂可以向客户提供一个接口,使得客户可以在不必指定产品的具体类型的情况下,创建多个产品族中的产品对象,强调的是“系列对象”的变化。

生成器模式Builder Pattern)把构造对象实例的逻辑移到了类的外部,在这个类的外部定义了这个类的构造逻辑。他把一个复杂对象的构造过程从对象的表示中分离出来。其直接效果是将一个复杂的对象简化为一个比较简单的目标对象。他强调的是产品的构造过程。

原型模式Prototype Pattern)和工厂模式一样,同样对客户隐藏了对象创建工作,但是,与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。

如何选择使用创建型模式

继续考虑上面提到的游戏开发场景,假定在这个游戏场景中我们使用到的有墙(Wall),屋子(Room),门(Door)几个部件。在这个过程中,同样是对象的创建问题,但是会根据所要解决的问题不同而使用不同的创建型模式。

如果在游戏中,一个屋子只允许有一个门存在,那么这就是一个使用Signleton模式的例子,确保只有一个Door类的实例被创建。解决的是对象创建个数的问题。

示例代码:

using System;

public sealed class SigletonDoor

{

    static readonly SigletonDoor instance=new SigletonDoor();

    static SigletonDoor()

    {

    }

    public static SigletonDoor Instance

    {

        get

        {

            return instance;

        }

    }

}

在游戏中需要创建墙,屋子的实例时,为了避免直接对构造器的调用而实例化类,这时就是工厂方法模式了,每一个部件都有它自己的工厂类。解决的是“单个对象”的需求变化问题。

示例代码:

using System;

public abstract class Wall

{

    public abstract void Display();

}

public class ModernWall:Wall

{

    public override void Display()

    {

        Console.WriteLine("ModernWall Builded");

    }

}

public abstract class WallFactory

{

    public abstract Wall Create();

}

public class ModernFactory:WallFactory

{

    public override Wall Create()

    {

        return new ModernWall();;

    }

}

在游戏场景中,不可能只有一种墙或屋子,有可能有现代风格(Modern),古典风格(Classical)等多系列风格的部件。这时就是一系列对象的创建问题了,是一个抽象工厂的例子。解决的是“系列对象”的需求变化问题。

示例代码:

using System;

public abstract class Wall

{

    public abstract void Display();

}

public class ModernWall:Wall

{

    public override void Display()

    {

        Console.WriteLine("ModernWall Builded");

    }

}

public class ClassicalWall:Wall

{

    public override void Display()

    {

        Console.WriteLine("ClassicalWall Builded");

    }

}

public abstract class Room

{

    public abstract void Display();

}

public class ModernRoom:Room

{

    public override void Display()

    {

        Console.WriteLine("ModernRoom Builded");

    }

}

public class ClassicalRoom:Room

{

    public override void Display()

    {

        Console.WriteLine("ClassicalRoom Builded");

    }

}

public abstract class AbstractFactory

{

    public abstract Wall CreateWall();

    public abstract Room CreateRoom();

}

public class ModernFactory:AbstractFactory

{

    public override Wall CreateWall()

    {

        return new ModernWall();

    }

    public override Room CreateRoom()

    {

        return new ModernRoom();

    }

}

public class ClassicalFactory:AbstractFactory

{

    public override Wall CreateWall()

    {

        return new ClassicalWall();

    }

    public override Room CreateRoom()

    {

        return new ClassicalRoom();

    }

}

如果在游戏场景中,构成某一个场景的算法比较稳定,例如:这个场景就是用四堵墙,一个屋子,一扇门来构成的,但具体是用什么风格的墙、屋子和门则是不停的变化的,这就是一个生成器模式的例子。解决的是“对象部分”的需求变化问题。

示例代码:

using System;

using System.Collections;

public class Director

{

    public void Construct( Builder builder )

    {

        builder.BuildWall();

        builder.BuildRoom();

        builder.BuildDoor();

    }

}

public abstract class Builder

{

    public abstract void BuildWall();

    public abstract void BuildRoom();

    public abstract void BuildDoor();

    public abstract GameScene GetResult();

}

public class GameBuilder : Builder

{

    private GameScene g;

    public override void BuildWall()

    {

        g = new GameScene();

        g.Add( "Wall" );

    }

    public override void BuildRoom()

    {

        g.Add( "Room" );

    }

    public override void BuildDoor()

    {

        g.Add( "Door" );

    }

    public override GameScene GetResult()

    {

        return g;

    }

}

public class GameScene

{

    ArrayList parts = new ArrayList();

    public void Add( string part )

    {

        parts.Add( part );

    }

    public void Display()

    {

        Console.WriteLine( " GameScene Parts:" );

        foreach( string part in parts )

            Console.WriteLine( part );

    }

}

如果在游戏中,需要大量的古典风格或现代风格的墙或屋子,这时可以通过拷贝一个已有的原型对象来生成新对象,就是一个原型模式的例子了。通过克隆来解决“易变对象”的创建问题。

示例代码:

using System;

public abstract class RoomPrototype

{

    public abstract RoomPrototype Clone();

}

public class ModernPrototype:RoomPrototype

{

    public override RoomPrototype Clone()

    {

        return (RoomPrototype)this.MemberwiseClone();

    }

}

public class ClassicalPrototype:RoomPrototype

{

    public override RoomPrototype Clone()

    {

        return (RoomPrototype)this.MemberwiseClone();

    }

}

究竟选用哪一种模式最好取决于很多的因素。使用Abstract FactoryPrototype PatternBuilder Pattern的设计比使用Factory Method的设计更加灵活,但是也更加复杂,尤其Abstract Factory需要庞大的工厂类来支持。通常,设计以使用Factory Method开始,并且当设计者发现需要更大的灵活性时,设计便会向其他设计模式演化,当你在多个设计模式之间进行权衡的时候,了解多个设计模式可以给你提供更多的选择余地。

总结

使用创建者模式是为了提高系统的可维护性和可扩展性,提高应对需求变化的能力!

参考文献:
《设计模式中文版》
《DesignPatternsExplained》
  idior 的《你了解创建者模式了吗? --- 创建者模式详解 》
  MSDN WebCast:http://www.microsoft.com/china/msdn/events/webcasts/shared/Webcast/MSDNWebCast.aspx

转载于:https://www.cnblogs.com/Aioria0622/archive/2007/11/21/967895.html

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

南方人第一次见到雪的样子。。。| 今日最佳

全世界只有3.14 %的人关注了青少年数学之旅(视频来源沙雕图,侵权删)

逆转是怎么发生的?

郑昀玩聚SR 20090527 曾几何时,香港警员的95%都参与了贪腐。当一个一个警员被迫加入行贿受贿行列中时,当其他公共服务机构也参与进来时,当民众不行贿就难以使用公权资源时,看上去似乎整个体系烂透了,无药可救&#xff…

MVVM架构~knockoutjs系列之包括区域级联列表的增删改

返回目录 这个例子我做了几次,之前总是有BUG,目前测试后,确定没有BUG才发上来的,主要功能是实现“我的银行”模块的增删改的功能,这个里面包括了级联列表的区域选择,这部分是难点,在开发过程中&…

ABP Vnext 4.4:统一Ef Core的DbContext/移除EF Core Migrations项目

Abp vnext 4.4出现了一个比较重大的变更:在Startup template中移除了EF Core Migrations项目,本文翻译自community.abp.io/articl由于本文发布的时候Abp vnext的版本还没有到4.4,所以本文演示了如何从4.4以前的版本移除EntityFrameworkCore.D…

史上最变态高考数学题,让99%的考生献上膝盖,看完我惊了......

全世界只有3.14 %的人关注了青少年数学之旅今天超模君想问大家一个问题:如果在撒哈拉大沙漠或者是西伯利亚上建造一个大型装置,以便向地球之外的其他星球的朋友们表明地球上存在有智慧的生命,最适当的装置是什么呢?勾股定理&#…

JS实现sleep功能 JS遍历document对象

标题:JS实现sleep功能 JS遍历document对象/*****************************************/ var elementName; function countTotalElement(node) { if(node.nodeType 1) { elementName elementName node.nodeValue "\r\n"; } …

C#操作Excel文件暨C#实现在Excel中将连续多列相同数据项合并

C#操作Excel文件(读取Excel,写入Excel) 看到论坛里面不断有人提问关于读取excel和导入excel的相关问题。闲暇时间将我所知道的对excel的操作加以总结,现在共享大家,希望给大家能够给大家带了一定的帮助。另外我们还要注意一些简单的问题1.exc…

#if DEBUG 和 if (env.IsDevelopment()) 的用法区别

咨询区 webwake:我发现预处理指令 #if DEBUG 和 Asp.NET Core环境变量名 都可以用于区分 debug/development 和 release/production 下的不同行为,请问他们都有哪些合适的应用场景?比如说某些场景下应该使用 预处理指令 而不是 环境变量 &…

数据结构 【实验3 链表基本操作】

实验3 链表基本操作 实验目的 1. 定义单链表的结点类型。 2. 熟悉对单链表的一些基本操作和具体的函数定义。 3. 通过单链表的定义掌握线性表的链式存储结构的特点。 4. 掌握循环链表和双链表的定义和构造方法。 实验内容 该…

第一次找工作感受!

20号南京有招聘会,我和几个同学就去了,去体验一下找工作是什么样子的,可能大家从第二天的报纸上已经看到了,不过如果你没有去现场,那种人山人海,直接要排山倒海,招聘单位写的什么基本上看不清了.. 转到上午10点一份没投,心里那个急,心想只要能要就行了,好像投出去就找到工作一样…

猪肉上的红章和蓝章有啥不同?| 今日趣图

全世界只有3.14 %的人关注了青少年数学之旅亲眼看到金字塔你才会意识到它有多大!(图源光消失的地方,侵权删)你女朋友的脸皮有多厚?(图源程序员新视界,侵权删)猪肉上的红章和蓝章有啥…

CSS工具列表

用户界面 I Like Your Color输入URL然后它会抓出其中的颜色并用16进制表示。CSS Multi-element Rollover Generator使用CSS和一个图片创建出一个翻转按钮的样式。CSS Rounded Box GeneratorRuthsarian Layouts6个CSS页面布局模板,包括颜色、标题等。Bluerobot Layou…

【开源】这可能是封装微信 API 最全的 .NET SDK 了

缘起今年公司某个项目需要全面接入微信支付 V3 版 API。起初觉得,2014 年微信支付就已上线了 V3 版 API,这都 2021 年了,就算官方不给力,怎么着社区也该有几个造好的 .NET 的轮子了吧?于是兴冲冲地到 NuGet 上开始搜索…

【Vegas原创】变换VS2005默认浏览器方法

右键任何aspx文件,在浏览方式中选择

如何避免和人尬聊?

全世界只有3.14 %的人关注了青少年数学之旅想要和别人有聊不完的话题?当然是多读书多看新闻了解新鲜有趣的事物啦如果你没有时间去阅读那么关注以下公号将会让你收获更多信息~长按二维码,选择“识别图中二维码”订阅。▼看鉴ID:kanjian6666▲长按二维码“…

java 中的 io 系统总结

Java 流在处理上分为字符流和字节流。字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组。 Java 内用 Unicode 编码存储字符,字符流处理类负责将外部的…

在VS Code中执行SQL查询,是怎样一种体验?

上次,我们演示了“如何使用Nuget包XPlot.Plotly.Interactive在.NET Interactive notebook中绘制图表”。这次,我们使用Nuget包Microsoft.DotNet.Interactive.SqlServer演示在.NET Interactive notebook中如何和SQL Server交互。安装Nuget包首先&#xff…

UVA 11090 Going in Cycle!! 二分答案 + bellman-ford

求平均值最小的环&#xff0c;如果平均值最小为x&#xff0c;则如果把每条边的权值都减(x1)&#xff0c;那么新图将会有负环&#xff0c;用bellman ford判断。 //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstri…

突发奇想:flash+.Net+数据库的一种构思

大家好!我是冯波!一个刚刚学了点编程的小伙子&#xff0c;爱好比较广泛。除了像其它男生那样喜欢踢足球&#xff0c;打篮球以外&#xff0c;自己也非常喜欢军事。什么《孙子兵法与三十六计》啊&#xff0c;《三国演义》啊总是百看不厌&#xff0c;就是没看过《武穆遗书》&#…