1、原型模式解决的问题

现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路.

前提:抽象变化较慢,实现变化较快(不稳定)

整个抽象的游戏设施建造系统相对变化较慢,本例中只有一个Build的创建方法,而Build内部的方法实现,该实现依赖与各种具体的实现,而这些实现变化的非常频繁,现在虽然只有现代风格和古典风格的房屋和道路的构建,而将来可能会卡通风格、另类风格等各种各样的对象加入到Build方法中来渲染游戏的背景.

在不考虑第三方容器组件(如Unity)和设计模式的情况下,为了快速完成这个任务,我们通常会用以下这种方式编码,代码如下:

    #region 抽象A
/// <summary>
/// 抽象的游戏设施建造系统
/// </summary>
public class BuildSystem
{
/// <summary>
/// Build方法的逻辑变化较慢(只需要创建2种风格的房屋和道路,总共8个对象),但是风格变化较快,由于需求变化,可能需要创建诸如卡通风格、另类风格等的房屋和道路
/// </summary>
public void Builld()
{
ModernHouse modernHouseA = new ModernHouse();
ModernHouse modernHouseB = new ModernHouse();
ModernRoad modernRoadA = new ModernRoad();
ModernRoad modernRoadB = new ModernRoad();
ClassicalHouse classicalBuildA = new ClassicalHouse();
ClassicalHouse classicalBuildB = new ClassicalHouse();
ClassicalRoad classicalRoadA = new ClassicalRoad();
ClassicalRoad classicalRoadB = new ClassicalRoad();
//下面是具体的对象实例操作,如现代化房屋虽然有两个实例,但是可能两个可能高矮、外形不同等
}
}
#endregion #region 实现细节b
/// <summary>
/// 现代风格的房屋
/// </summary>
public class ModernHouse { } /// <summary>
/// 现代风格的道路
/// </summary>
public class ModernRoad { } /// <summary>
/// 古典风格的房屋
/// </summary>
public class ClassicalHouse { } /// <summary>
/// 古典风格的道路
/// </summary>
public class ClassicalRoad { }
#endregion

从oop的角度分析上面的代码,可以理解为抽象的游戏系统直接依赖具体的实现细节(现代风格和古典风格的房屋和道路),如下图:

这时客户端的调用代码如下:

    /// <summary>
/// Prototype原型模式-创建型模式
/// </summary>
class Program
{
static void Main(string[] args)
{
BuildSystem buildSystem = new BuildSystem();
buildSystem.Builld();
}
}

这种设计方式的弊端显而易见,Build方法显得很无力,这个时候增加了一个新的需求,如下:

客户端需要构建一种卡通风格和另类风格的道路和房屋,但是Build方法的主逻辑还是不变,同样是(创建两种风格的房屋和道路,共8个对象).

这时Build方法显得很无力,只能创建一种特定逻辑的游戏背景建筑.(当然你可以在BuildSystem中新添一种新的Build方法来满足需求,但是这种方式的代码的重用性差)而且,掉到了,抽象依赖于实现的坑里面去了,这个时候我们就需要对代码进行重构,进行依赖倒置.如下图:

对所有的Build方法中的8个实例(实现细节b)进行抽象,让它们依赖于抽象B,让Build方法(抽象A)也依赖于抽象B,代码如下:

    #region 抽象A
/// <summary>
/// 抽象的游戏设施建造系统
/// </summary>
public class BuildSystem
{
/// <summary>
/// Build方法的逻辑变化较慢(只需要创建2种风格的房屋和道路,总共8个对象),但是风格变化较快,由于需求变化,可能需要创建诸如卡通风格、另类风格等的房屋和道路
/// </summary>
public void Builld(House houseone, House houseTwo,Road roadone, Road roadtwo)
{
House modernHouseA = houseone.Clone();
House modernHouseB = houseone.Clone();
Road modernRoadA = roadone.Clone();
Road modernRoadB = roadone.Clone();
House classicalBuildA = houseTwo.Clone();
House classicalBuildB = houseTwo.Clone();
Road classicalRoadA = roadtwo.Clone();
Road classicalRoadB = roadtwo.Clone();
//下面是具体的对象实例操作,如现代化房屋虽然有两个实例,但是可能两个可能高矮、外形不同等
}
}
#endregion #region 抽象B
/// <summary>
/// 抽象房屋
/// </summary>
public abstract class House
{
/// <summary>
/// 抽象的House的Clone方法,用于构建House的多个实例,如果抽象A只需要一个实现b的一个实例,则不需要该方法
/// </summary>
/// <returns></returns>
public abstract House Clone();
} /// <summary>
/// 抽象道路
/// </summary>
public abstract class Road
{
/// <summary>
/// 抽象的Road的Clone方法,用于构建Road的多个实例,如果抽象A只需要一个实现b的一个实例,则不需要该方法
/// </summary>
/// <returns></returns>
public abstract Road Clone();
}
#endregion #region 实现细节b
/// <summary>
/// 现代风格的房屋
/// </summary>
public class ModernHouse : House
{
public override House Clone()
{
//实现ModernHouse的浅拷贝,如果当前对象中含有数组等,则需要使用序列化的方式(深拷贝)实现对象的克隆,否则当一个对象实例修改了数组,另一个对象实例会共享该数组
return (ModernHouse)MemberwiseClone();
}
} /// <summary>
/// 现代风格的道路
/// </summary>
public class ModernRoad : Road
{
public override Road Clone()
{
return (ModernRoad)MemberwiseClone();
}
} /// <summary>
/// 古典风格的房屋
/// </summary>
public class ClassicalHouse : House
{
public override House Clone()
{
return (House)MemberwiseClone();
}
} /// <summary>
/// 古典风格的道路
/// </summary>
public class ClassicalRoad: Road
{
public override Road Clone()
{
return (ClassicalRoad)MemberwiseClone();
}
} /// <summary>
/// 卡通风格的房屋
/// </summary>
public class CartoonHouse : House
{
public override House Clone()
{
return (CartoonHouse)MemberwiseClone();
}
} /// <summary>
/// 卡通风格的道路
/// </summary>
public class CartoonRoad : Road
{
public override Road Clone()
{
return (CartoonRoad)MemberwiseClone();
}
} /// <summary>
/// 另类风格的房屋
/// </summary>
public class AlternativeHouse : House
{
public override House Clone()
{
return (AlternativeHouse)MemberwiseClone();
}
} /// <summary>
/// 另类风格的道路
/// </summary>
public class AlternativeRoad : Road
{
public override Road Clone()
{
return (AlternativeRoad)MemberwiseClone();
}
}
#endregion

这时客户端的调用代码如下:

    class Program
{
static void Main(string[] args)
{
BuildSystem buildSystem = new BuildSystem();
//构建卡通风格和另类风格的房屋和道路
buildSystem.Builld(new CartoonHouse(), new AlternativeHouse(), new CartoonRoad(), new AlternativeRoad());
//构建现代风格和古典风格的房屋和道路
buildSystem.Builld(new ModernHouse(),new ClassicalHouse(),new ModernRoad(),new ClassicalRoad());
}
}

ok,重构后的代码,在抽象A相对稳定的情况,通过对实现细节b的抽象,让实现细节b和抽象A都依赖于抽象B,完成了依赖倒置,实现了代码new的解耦,这就是原型模式!

关于原型模式的几个要点:

1、Prototype模式用于隔离类对象的使用者和具体类型(易变类)的之间的耦合关系,但是这些易变类必须拥有稳定的接口.

2、Prototype模式对于"如何创建易变类的对象"采用"原型克隆"的方式来做,它使我们能非常灵活动态的创建某些拥有"稳定接口"的新对象.所需的工作仅仅是创建一个新类的对象即原型,然后在需要的地方不断的Clone.

3、Prototype模式的Clone方法可以利用Object自带的MemberwiseClone方法,注:该方法只能用于比较简单的类,只能实现浅拷贝,如果类中包含数组等引用类型,则需要使用序列化方法来实现类型的深拷贝

Prototype原型模式(创建型模式)的更多相关文章

  1. Prototype原型(创建型模式)

    依赖关系的倒置:抽象不应该依赖于实现的细节,实现细节应该依赖于抽象. 原型模式的定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.prototype模式允许一个对象再创建另外一个可 ...

  2. FactoryMethod工厂方法模式(创建型模式)

    1.工厂方法模式解决的问题 现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路. 前提:抽象变化较慢,实现变化较快(不稳定) 整个抽象的游戏设施建造系统相对变化较慢,本例中只 ...

  3. 设计模式(五):PROTOTYPE原型模式 -- 创建型模式

    1.定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 2.适用场景 原型模式的主要思想是基于现有的对象克隆一个新的对象出来,一般是有对象的内部提供克隆的方法,通过该方法返回一个对 ...

  4. 工厂方法模式——创建型模式02

    1. 简单工厂模式     在介绍工厂方法模式之前,先介绍一下简单工厂模式.虽然简单工厂模式不属于GoF 23种设计模式,但通常将它作为学习其他工厂模式的入门,并且在实际开发中使用的也较为频繁. (1 ...

  5. 设计模式(二): BUILDER生成器模式 -- 创建型模式

    1.定义 将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式. 2.适用场景 1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式 ...

  6. 建造者模式与原型模式/builder模式与prototype模式/创建型模式

    建造者模式 定义 用于简化复杂对象的创建 JDK中的建造者模式 java.lang.StringBuilder中的append()方法,每次调用后返回修改后的对象本身. public StringBu ...

  7. C#面向对象设计模式纵横谈——6.Prototype 原型模式(创建型模式)

    动机(Motivation) 在软件系统中,经常面临着“某些结构复杂的对象”的创建工作.由于需求的变化,这些对象经常面临着剧烈的变化,但他们却拥有比较稳定一致的接口. 如何应对这种变化?如何向“客户程 ...

  8. C#设计模式--工厂模式(创建型模式)

    一.简单工厂模式(UML类图): 核心类代码: public class Calc { public double NumberA { get; set; } public double Number ...

  9. 工厂模式/factory模式/创建型模式

    工厂模式 普通工厂模式 原本需要new出来的对象,通过一个类的方法去搞定,Factory.build(parameter),类似这种. public interface Sender { public ...

随机推荐

  1. Kotlin零碎总结

    1.对于Kotlin的包方法其实对应Java而言是静态方法,如Entrance.kt文件的外部有fun main(...方法,那么编译成字节码后就是Java的Entrance类里有public sta ...

  2. HDFS块文件和存放目录的关系

    详情请参见DatanodeUtil.java中的函数idToBlockDir(File root, long blockId). 如果block文件没有放在正确的目录下,则DataNode会出现&qu ...

  3. 20145232 韩文浩 《Java程序设计》第4周学习总结

    教材学习内容总结 · Chapter 继承与多态 继承:避免多个类间重复定义共同行为.继承可以理解为一个对象从另一个对象获取属性的过程. 所有Java的类均是由java.lang.Object类继承而 ...

  4. (动态规划)免费馅饼--hdu--1176

    http://acm.hdu.edu.cn/showproblem.php?pid=1176 免费馅饼 Time Limit: 2000/1000 MS (Java/Others)    Memory ...

  5. thrift使用总结

    转自 http://blog.csdn.net/qq_27784479/article/details/73250958 Apache Thrift软件框架用于可扩展的跨语言服务开发,简单来说就是RP ...

  6. Swagger生成WebAPI文档

    WebAPI2.0 项目可以使用Swagger能够轻易查看API文档,查看以下配置 1.打开程序包管理控制台输入: Install-Package Swashbuckle 2.在对应项目里的App_S ...

  7. 使用Windows 8 Pro密钥光盘安装Windows 8.1 Pro

    在Windows 8.1发布接近半年的时候,自己终于腾出来了时间,准备升级一下自己的系统.作为一名极度强迫症患者,加上校园网的悲剧网速,最后决定使用光盘镜像全新安装而不是通过应用商店的升级. Figu ...

  8. STL容器之一vector

    STL中最简单也是最有用的容器之一是vector<T>类模板,称为向量容器,是序列类型容器中的一种. 1.vector<T> 对象的基本用法(1)声明:vector<ty ...

  9. mod与%的区别

    mod与%的区别 %与mod的区别: %出来的数有正有负,符号取决于左操作数,而mod只能是正: 所以要用%来计算mod的话就要用这样的公式:a mod b = (a % b + b) % b: 括号 ...

  10. Codeforces Round #265 (Div. 2) E. Substitutes in Number

    http://codeforces.com/contest/465/problem/E 给定一个字符串,以及n个变换操作,将一个数字变成一个字符串,可能为空串,然后最后将字符串当成一个数,取模1e9+ ...