c# - OOP 中的表达类型组合
问题描述
假设我们要编写一个 RPG 游戏,它有 3 种基本角色类型:战士、法师和弓箭手。我们还结合了骑士、圣骑士和游侠等角色类型。在 TypeScript 中,我们可以为这样的字符描述接口:
// fighter can fight
// mage can cast
// archer can shoot
// paradin can cast and fight
// knight can fight and shoot
// ranger can cast and shoot
type Fighter = {fight: () => string}
type Mage = {cast: () => string}
type Archer = {shoot: () => string}
type Knight = Fighter & Archer
type Paladin = Fighter & Mage
type Ranger = Archer & Mage
问题是如何仅使用 OOP 技术来实现这些接口(假设我们正在使用 C# 等主流 OOP 语言)?
在没有行为重复的情况下,我没有成功地用继承来表达这一点。目前我看到的唯一方法是:
class Paladin {
constructor(private fighter: Fighter, private mage: Mage) {}
fight() {this.fighter.fight()}
cast() {this.mage.cast()}
}
但我不喜欢这种方法,因为任何时候我想创造一个圣骑士,我也必须创造一个法师和一个战士,基本上是同一个人
解决方案
也许试着把你的作文推得更远一点。你只需要一种具有不同能力的类型,例如:
public class Hero
{
private readonly string name;
private readonly IEnumerable<IHeroAbility> abilities;
public Hero(string name, [Optional] IEnumerable<IHeroAbility> abilities)
{
this.name = name;
this.abilities = abilities ?? new List<IHeroAbility> { new OhCrap() };
}
public void Attack()
{
Console.WriteLine(name);
foreach (var ability in abilities) ability.Execute();
Console.WriteLine();
}
}
现在准备可用的能力:
public interface IHeroAbility
{
void Execute();
}
public class SwingSwordAbility : IHeroAbility
{
public void Execute()
{
Console.WriteLine("And with all his might the hero swung his sword down onto his opponent...");
}
}
public class ShootArrowAbility : IHeroAbility
{
public void Execute()
{
Console.WriteLine("The hero loads an arrow into his bow without blinking and launches it with fierce speed towards his opponant...");
}
}
public class CastFireBallAbility : IHeroAbility
{
public void Execute()
{
Console.WriteLine("The hero reaches deep into the underverse and hurls a ball of fire towards his opponant...");
}
}
public class OhCrap : IHeroAbility
{
public void Execute()
{
Console.WriteLine("The hero pats his pockets as if he forgot something at home...");
}
}
然后组成你的英雄类型:
class Program
{
static void Main(string[] args)
{
IHeroAbility swingSwordAbility = new SwingSwordAbility();
IHeroAbility shootArrowAbility = new ShootArrowAbility();
IHeroAbility castFireBallAbility = new CastFireBallAbility();
var fighter = new Hero("The Fighter", new[] { swingSwordAbility });
fighter.Attack();
var mage = new Hero("The Mage", abilities: new[] { castFireBallAbility });
mage.Attack();
var archer = new Hero("The Archer", abilities: new[] { shootArrowAbility });
archer.Attack();
var knight = new Hero("The Knight", abilities: new[] { swingSwordAbility, shootArrowAbility });
knight.Attack();
var paladin = new Hero("The Paladin", abilities: new[] { swingSwordAbility, castFireBallAbility });
paladin.Attack();
var ranger = new Hero("The Ranger",abilities: new[] { shootArrowAbility, castFireBallAbility });
ranger.Attack();
}
}
如果您想要更明确的操作组,您可以将您的Hero
类修改为以下内容:
public class Hero
{
private readonly string name;
private readonly IEnumerable<IHeroAbility> meleeAbilities;
private readonly IEnumerable<IHeroAbility> magicAbilities;
private readonly IEnumerable<IHeroAbility> rangedAbilities;
public Hero(
string name,
[Optional] IEnumerable<IHeroAbility> meleeAbilities,
[Optional] IEnumerable<IHeroAbility> magicAbilities,
[Optional] IEnumerable<IHeroAbility> rangedAbilities)
{
this.name = name;
var defaultAbilities = new List<IHeroAbility> { new OhCrap() };
this.meleeAbilities = meleeAbilities ?? defaultAbilities;
this.magicAbilities = magicAbilities ?? defaultAbilities;
this.rangedAbilities = rangedAbilities ?? defaultAbilities;
}
public void MeleeAttack()
{
var ability = meleeAbilities.First();
Console.WriteLine(name);
ability.Execute();
}
public void MagicAttack()
{
var ability = magicAbilities.First();
Console.WriteLine(name);
ability.Execute();
}
public void RangedAttack()
{
var ability = rangedAbilities.First();
Console.WriteLine(name);
ability.Execute();
}
}
然后,您可以开始构建它以包含更复杂的逻辑,例如与能力、冷却时间、能力选择等相关的成本等。
希望这可以帮助!
推荐阅读
- android - 我怎样才能得到firebase中键、值对的计数?
- c# - 如何用正则表达式类替换两个单词之间的字符串,包括这些单词
- python - 使用 python 套接字的 FIN/ACK 通知
- reactjs - 如何使用socket.io在本机反应中为Web基础应用程序创建与后端服务器的聊天连接?
- python - Python:尽管明显存在,但看不到功能
- vb.net - 是否可以在未安装引擎的情况下使用 ADODB/OleDB 连接?
- ruby-on-rails - 如何在变量中添加数组并通过get方法将其发送到url
- excel - 过滤列表范围内的唯一值
- c# - 当我使用参数化查询时出现此错误(必须声明标量变量@“regNo”)
- java - 尝试通过android调用JSON api时出现无效请求错误