I'll start with this monster "Monster" code from Rust for Rubyist :
trait Monster {
fn attack(&self);
fn new() -> Self;
}
struct IndustrialRaverMonkey {
life: int,
strength: int,
charisma: int,
weapon: int,
}
struct DwarvenAngel {
life: int,
strength: int,
charisma: int,
weapon: int,
} ...
impl Monster for IndustrialRaverMonkey { ...
impl Monster for DwarvenAngel { ...
I worry about duplication of code. In Java I would create interface that define attack
method and base class with all that parameters ( life
, strength
, charisma
, weapon
). I will do same thing in C++ with abstract class. I can find some ugly and unintuitive ways to work around this problem, but is there a good way to reduce code? I mean, to keep it scalable and readable.
Another approach, which favors composition, and from which is easier to diverge implementations if needed (eg, the Characteristics
for DwarvenAngel
require an additional field):
trait Monster {
fn attack(&self);
}
struct Characteristics {
life: int,
strength: int,
charisma: int,
weapon: int,
}
struct IndustrialRaverMonkey {
characteristics: Characteristics
}
struct DwarvenAngel {
characteristics: Characteristics
}
fn same_attack(c: Characteristics) {
fail!("not implemented")
}
impl Monster for IndustrialRaverMonkey {
fn attack(&self) {
same_attack(self.characteristics)
}
}
impl Monster for DwarvenAngel {
fn attack(&self) {
same_attack(self.characteristics)
}
}
Or, you can have an enum represent your monster types, very similar to AB's answer:
trait Monster {
fn attack(&self);
}
struct Characteristics {
life: int,
strength: int,
charisma: int,
weapon: int,
}
enum Monsters {
IndustrialRaverMonkey(Characteristics),
DwarvenAngel(Characteristics),
}
fn same_attack(_: &Characteristics) {
fail!("not implemented")
}
impl Monster for Monsters {
fn attack(&self) {
match *self {
IndustrialRaverMonkey(ref c) => same_attack(c),
DwarvenAngel(ref c) => same_attack(c)
}
}
}
Would you consider something like this an acceptable solution?
trait Actor {
fn attack(&self);
}
enum MonsterId {
IndustrialRaverMonkey,
DwarvenAngel
}
struct Monster {
life: int,
strength: int
}
impl Monster {
fn new(id: MonsterId) -> Monster {
match id {
IndustrialRaverMonkey =>
Monster { life: 12, strength: 8 },
DwarvenAngel =>
Monster { life: 18, strength: 12 }
}
}
}
impl Actor for Monster {
fn attack(&self) {}
}
Updated with a better example.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.