OO中的多态是子类各有各的逻辑,调用时用父类类型但传入子类, 保障代码简约的同时大大提高扩展性,是OO的三大基本特征之一.
在下面的代码,使用两个特型就模拟出了类似的效果.
特型Spawn实体生成器有两个实现: EntityCommands普通实体生成器和RelatedSpawnerCommands关系实体生成器.
这里核心是实体生成器Spawn可以生成挂件Widgets.
不管是挂件还是实体生成器都是特型,后期就算新增了其他的实体生成器,这块的代码都不用修改,灵活.
/// An extension trait for spawning UI widgets.
pub trait Widgets {
/// Spawn a simple button with text.
fn button(&mut self, text: impl Into<String>) -> EntityCommands;
/// Spawn a simple header label. Bigger than [`Widgets::label`].
fn header(&mut self, text: impl Into<String>) -> EntityCommands;
/// Spawn a simple text label.
fn label(&mut self, text: impl Into<String>) -> EntityCommands;
}
impl<T: Spawn> Widgets for T {
fn button(&mut self, text: impl Into<String>) -> EntityCommands {
// 这里调用的是T::spawn,也就是子类的逻辑.
self.spawn((
Name::new("Button"),
Button,
Node {
width: Px(200.0),
height: Px(65.0),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
..default()
},
BackgroundColor(NODE_BACKGROUND),
InteractionPalette {
none: NODE_BACKGROUND,
hovered: BUTTON_HOVERED_BACKGROUND,
pressed: BUTTON_PRESSED_BACKGROUND,
},
children![(
Name::new("Button Text"),
Text(text.into()),
TextFont::from_font_size(40.0),
TextColor(BUTTON_TEXT),
)],
))
}
fn header(&mut self, text: impl Into<String>) -> EntityCommands { }
fn label(&mut self, text: impl Into<String>) -> EntityCommands { }
}
/// An internal trait for types that can spawn entities.
/// This is here so that [`Widgets`] can be implemented on all types that
/// are able to spawn entities.
/// Ideally, this trait should be [part of Bevy itself](https://github.com/bevyengine/bevy/issues/14231).
trait Spawn {
fn spawn<B: Bundle>(&mut self, bundle: B) -> EntityCommands;
}
impl Spawn for Commands<'_, '_> {
fn spawn<B: Bundle>(&mut self, bundle: B) -> EntityCommands {
self.spawn(bundle)
}
}
impl<R: Relationship> Spawn for RelatedSpawnerCommands<'_, R> {
fn spawn<B: Bundle>(&mut self, bundle: B) -> EntityCommands {
self.spawn(bundle)
}
}