设计模式之美:Type Object(类型对象)

简介:

索引

意图

允许在运行时动态灵活的创建新的 "类",而这些类的实例代表着一种不同的对象类型。

Allow the flexible creation of new “classes” by creating a single class, each instance of which represents a different type of object.

结构

Type Object 模式包含两个具体类。一个用于描述对象,另一个用于描述类型。每个对象都包含一个指向其类型的指针。

参与者

TypeClass

  • 是 TypeObject 的种类。
  • 每个种类都会有一个单独的类。

TypeObject

  • 是 TypeClass 的实例。
  • 代表着一种对象。定义一种对象所包含的属性和行为。

适用性

当以下情况成立时可以使用 Type Object 模式:

  • 类的实例需要根据它们的通用属性或者行为进行分组。
  • 类需要为每个分组定义一个子类来实现该分组的通用属性和行为。
  • 类需要大量的子类或者多种变化的子类甚至无法预期子类的变化。
  • 你需要有能力在运行时创建一些无法在设计阶段预测的新的分组。
  • 你需要有能力在类已经被实例化的条件下更改一个对象的子类。

效果

  • 运行时创建新的类型对象。
  • 避免子类膨胀。
  • 客户程序无需了解实例与类型的分离。
  • 可以动态的更改类型。

相关模式

  • Type Object 模式有些类似于 Strategy 和 State 模式。这三种模式都是通过将对象内部的一些行为代理到外部的对象中。Stategy 和 State 通常是纯行为的代理,而 Type Object 则包含更多个共享数据状态。State 可以被频繁的更改,Type Object 则很少被改变。Strategy 通常仅包含一个职责,Type Object 则通常包含多个职责。
  • Type Object 的实现与 Bridge 模式中的 Abstraction 和 Implementor 的关系很像。区别在于,客户程序可以与 Type Object 直接协作,而不会直接与 Implementor 进行交互。
  • Type Object 有点像 Flyweight 一样处理它的对象。两个对象使用相同的 Type Object 可能看起来是使用的各自的实例,但实际是共享的对象。
  • Type Object 可以解决多个对象共享数据和行为的问题。类似的问题也可以用 Prototype 模式来解决。

实现

实现方式(一):Type Object 的经典介绍。

  • TypeClass - Movie
  • TypeObject - Star Wars, The Terminator, Independence Day
  • Class - Videotape
  • Object - John's Star Wars, Sue's Star Wars
复制代码
 1 namespace TypeObjectPattern.Implementation1
 2 {
 3   public class Movie
 4   {
 5     public string Title { get; set; }
 6     public float RentalPrice { get; set; }
 7   }
 8 
 9   public class Videotape
10   {
11     public Videotape(Movie movie)
12     {
13       this.Movie = movie;
14     }
15 
16     public Movie Movie { get; private set; }
17 
18     public Customer Renter { get; private set; }
19     public bool IsRented { get; private set; }
20 
21     public void RentTo(Customer customer)
22     {
23       IsRented = true;
24       Renter = customer;
25       Renter.ChargeForRental(this.Movie.RentalPrice);
26     }
27   }
28 
29   public class Customer
30   {
31     public string Name { get; set; }
32 
33     public void ChargeForRental(float rental)
34     {
35       // pay money
36     }
37   }
38 
39   public class Client
40   {
41     public void TestCase1()
42     {
43       Customer john = new Customer() { Name = "John" };
44       Customer sue = new Customer() { Name = "Sue" };
45 
46       Movie starWars = new Movie()
47       {
48         Title = "Star Wars",
49         RentalPrice = 100,
50       };
51       Movie terminator = new Movie()
52       {
53         Title = "The Terminator",
54         RentalPrice = 200,
55       };
56 
57       Videotape starWarsVideotapeForJohn = new Videotape(starWars);
58       starWarsVideotapeForJohn.RentTo(john);
59 
60       Videotape starWarsVideotapeForSue = new Videotape(starWars);
61       starWarsVideotapeForSue.RentTo(john);
62 
63       Videotape terminatorVideotapeForJohn = new Videotape(terminator);
64       terminatorVideotapeForJohn.RentTo(john);
65     }
66   }
67 }
复制代码

实现方式(二):Type Object 在游戏设计中的使用。

想象我们正在制作在一个虚拟角色扮演游戏。我们的任务是设计一些邪恶的怪兽(Monster)来试图杀掉我们的英雄(Hero)。怪兽有着一些不同的属性,例如生命值(Health)、攻击力(Attacks)、图像、声音等,但以举例为目的我们仅考虑前两个属性。

游戏中的每个怪兽都有自己的生命值。生命值从满血开始,每次怪兽被创伤,生命值减少。怪兽会有一个用于描述攻击的字符串,当怪兽攻击英雄时,这个字符串会被显示到用户屏幕上。

游戏设计师告诉我们,怪兽会有不同的品种(Breed),例如:猛龙(Dragon)和巨魔(Troll)。每个怪兽品种都描述了一种怪兽,在一个场景下会有多个同一种的怪兽遍布在地牢(Dungeon)中。

怪兽的品种(Breed)决定的怪兽的起始生命值,比如猛龙(Dragon)的生命值会比巨魔(Troll)的高,以使猛龙更难被杀掉。同时,同一个品种的怪兽的攻击字符串也是相同的。

通过典型的 OO 设计,我们能得到下面这段代码:

复制代码
 1 namespace TypeObjectPattern.Implementation2
 2 {
 3   public abstract class Monster
 4   {
 5     public Monster(int startingHealth)
 6     {
 7       Health = startingHealth;
 8     }
 9 
10     public int Health { get; private set; }
11     public abstract string AttackString { get; }
12   }
13 
14   public class Dragon : Monster
15   {
16     public Dragon()
17       : base(500)
18     {
19     }
20 
21     public override string AttackString
22     {
23       get { return "The dragon breathes fire!"; }
24     }
25   }
26 
27   public class Troll : Monster
28   {
29     public Troll()
30       : base(300)
31     {
32     }
33 
34     public override string AttackString
35     {
36       get { return "The troll clubs you!"; }
37     }
38   }
39 
40   public class Client
41   {
42     public void TestCase2()
43     {
44       Monster dragon = new Dragon();
45       Monster troll = new Troll();
46     }
47   }
48 }
复制代码

这段代码浅显易懂,使用继承的方式设计类的层级结构。一个 Dragon 是一个 Monster,满足了 "is a" 的关系。每一个怪物的品种都会用一个子类来实现。

如果游戏中有成百上千的怪物种类,则类的继承关系变得庞大。同时也意味着,增加新的怪物品种就需要增加新的子类代码。

这是可以工作的,但并不是唯一的选择。我们可以尝试另外一种架构。

因为变化较多的部分是品种(Breed)的属性配置,包括生命值和攻击字符串。

所以我们可以将品种(Breed)抽取成单独的类,每个怪物类(Monster)包含一个品种类(Breed)。

Breed 类用于定义 Monster 的 "type"。每一个 Breed 的实例描述着一种 Monster 对象的概念上的 "type"。

复制代码
 1 namespace TypeObjectPattern.Implementation3
 2 {
 3   public class Breed
 4   {
 5     public int Health { get; set; }
 6     public string AttackString { get; set; }
 7   }
 8 
 9   public class Monster
10   {
11     private Breed _breed;
12 
13     public Monster(Breed breed)
14     {
15       _breed = breed;
16     }
17 
18     public int Health
19     {
20       get { return _breed.Health; }
21     }
22 
23     public string AttackString
24     {
25       get { return _breed.AttackString; }
26     }
27   }
28 
29   public class Client
30   {
31     public void TestCase3()
32     {
33       Breed dragonBreed = new Breed()
34       {
35         Health = 500,
36         AttackString = "The dragon breathes fire!",
37       };
38       Breed trollBreed = new Breed()
39       {
40         Health = 300,
41         AttackString = "The troll clubs you!",
42       };
43 
44       Monster dragon = new Monster(dragonBreed);
45       Monster breed = new Monster(trollBreed);
46     }
47   }
48 }
复制代码

Type Object 在这里的优势在于,我们可以定义新的类型的怪物,而不用修改代码。并且可以在运行时动态生成新的对象和修改对象的属性。

参考资料








本文转自匠心十年博客园博客,原文链接:http://www.cnblogs.com/gaochundong/p/design_pattern_type_object.html,如需转载请自行联系原作者


目录
相关文章
|
17天前
|
存储 消息中间件 人工智能
【05】AI辅助编程完整的安卓二次商业实战-消息页面媒体对象(Media Object)布局实战调整-按钮样式调整实践-优雅草伊凡
【05】AI辅助编程完整的安卓二次商业实战-消息页面媒体对象(Media Object)布局实战调整-按钮样式调整实践-优雅草伊凡
64 11
【05】AI辅助编程完整的安卓二次商业实战-消息页面媒体对象(Media Object)布局实战调整-按钮样式调整实践-优雅草伊凡
|
5月前
|
设计模式 监控 Java
并发设计模式实战系列(8):Active Object
🌟 大家好,我是摘星!🌟今天为大家带来的是并发设计模式实战系列,第8章,废话不多说直接开始~
84 0
并发设计模式实战系列(8):Active Object
|
5月前
|
设计模式 安全 Java
并发设计模式实战系列(12):不变模式(Immutable Object)
🌟 大家好,我是摘星!🌟今天为大家带来的是并发设计模式实战系列,第十二章,废话不多说直接开始~
100 0
|
3月前
|
JavaScript 前端开发 开发者
讲述Vue框架中用于对象响应式变化的Object.defineProperty函数。
综上所述,Vue.js通过 `Object.defineProperty()`提供了强大的响应式能力,使得状态管理变得简洁高效。这种能力是Vue.js受到广大开发者青睐的重要原因之一。尽管Vue 3.x使用Proxy替代了该方法,但对于Vue 2.x及其之前版本,`Object.defineProperty()`是理解Vue.js内部工作机制不可或缺的一部分。
130 27
|
7月前
|
设计模式 存储 Java
【再谈设计模式】备忘录模式~对象状态的守护者
备忘录模式属于行为型设计模式。它的主要目的是在不破坏对象封装性的前提下,捕获并外部化一个对象的内部状态,以便之后可以将该对象恢复到这个状态。原发器(Originator):创建一个备忘录,用于记录当前时刻它的内部状态。原发器还可以使用备忘录来恢复其内部状态。备忘录(Memento):存储原发器对象的内部状态。备忘录应该防止原发器以外的其他对象访问其内部状态。负责人(Caretaker):负责保存备忘录,但不能对备忘录的内容进行操作或检查。
278 82
|
8月前
|
设计模式 供应链 安全
【再谈设计模式】中介者模式 - 协调对象间交互的枢纽
中介者模式定义了一个中介对象来封装一组对象之间的交互方式。中介者使得各对象之间不需要显式地相互引用,从而降低了它们之间的耦合度。它通过将对象之间的交互逻辑集中到中介者对象中,使得系统的结构更加清晰,易于维护和扩展。
157 18
【再谈设计模式】中介者模式 - 协调对象间交互的枢纽
|
8月前
|
设计模式 Java Go
【再谈设计模式】状态模式~对象行为的状态驱动者
状态模式属于行为型设计模式。它将对象的行为封装在不同的状态类中,使得对象在不同的状态下表现出不同的行为。上下文(Context):这是一个包含状态对象的类,它定义了客户感兴趣的接口,并维护一个具体状态对象的引用。上下文将操作委托给当前的状态对象来处理。抽象状态(State):这是一个抽象类或者接口,它定义了一个特定状态下的行为接口。所有具体的状态类都实现这个接口。具体状态(Concrete State):这些是实现抽象状态接口的类,每个具体状态类实现了与该状态相关的行为。
194 18
|
9月前
|
安全 Java
Object取值转java对象
通过本文的介绍,我们了解了几种将 `Object`类型转换为Java对象的方法,包括强制类型转换、使用 `instanceof`检查类型和泛型方法等。此外,还探讨了在集合、反射和序列化等常见场景中的应用。掌握这些方法和技巧,有助于编写更健壮和类型安全的Java代码。
468 17
|
7月前
|
前端开发 数据处理
对象数据的读取,看这一篇就够了!Object.keys()、Object.values()和Object.entries()用法详解;如何获取对象原型链上的属性
Object.keys()、Object.values()和Object.entries()都是利于对象操作的便捷方法,能有效提升数据处理的效率。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
8月前
|
设计模式 算法 Java
【再谈设计模式】访问者模式~操作对象结构的新视角
  访问者模式是一种行为设计模式,旨在解决对象结构与操作逻辑的耦合问题。在软件系统开发中,当面临复杂的对象结构(如多种类型对象组成的树形或图形结构),且需要对这些对象执行不同操作时,传统方式将操作直接写在对象类中会导致类职责过多,不利于维护和扩展。而访问者模式通过将操作与对象结构分离,允许在不改变现有对象结构的情况下定义新操作,元素接受访问者访问,访问者定义对不同类型元素的操作逻辑,从而为应对这种复杂情况提供了有效的解决方案。
107 0

热门文章

最新文章