英文:
Design pattern for object assuming new features at runtime?
问题
假设我有一个名为 House
的类。
我想要给我的房屋添加规格,比如一个 Garage
,一个 SwimmingPool
或者一个 Garden
,每个规格都带有一组自己的新方法。
如果我使用继承,我会有子类 HouseWithGarage
,HouseWithSwimmingPool
和 HouseWithGarden
。但如果我希望一个对象同时有一个车库和一个花园呢?如果以后我想在运行时为同一个对象添加一个游泳池呢?
显然继承在这里不适用。您是否知道适用于这种问题的任何设计模式?
英文:
Suppose I have a class House
.
I want to be adding specifications to my house, like a Garage
, a SwimmingPool
or a Garden
, each coming with its own set of new methods.
If I used inheritance, I would have subclasses HouseWithGarage
, HouseWithSwimmingPool
and HouseWithGarden
. But what if I wanted to have an object with a garage and a garden at the same time? What if later I wanted to add a swimmingpool to that same object at runtime?
Obviously inheritance doesn't work well here. Are you aware of any design pattern appropriate for this kind of problem?
答案1
得分: 2
最接近描述您所寻找的模式是组合模式,该模式在Gamma等人的《设计模式》一书中有所描述。
(图片已省略)
来自Gamma的书中:
Component(组件)
- 声明组合中对象的接口。
- 根据需要,为所有类共有的接口实现默认行为。
- 声明访问和管理其子组件的接口。
- 如果适用,还可以为访问组件递归结构中的父组件定义接口,并在需要时实现该接口。
Leaf(叶节点)
- 代表组合中的叶对象。叶节点没有子节点。
- 为组合中的原始对象定义行为。
Composite(复合对象)
- 为具有子节点的组件定义行为。
- 存储子组件。
- 在组件接口中实现与子节点相关的操作。
House
将是一个 Component
(组件)。Garage
、Garden
和 SwimmingPool
将根据它们是否由子组件组成而分别是 Leaf
(叶节点)或 Composite
(复合对象)。
不用说(?),这些接口除了 operation()
外还可以有许多操作。
英文:
The pattern that closest describes what you are looking for is the Composite Pattern, described in "Design Patterns" by Gamma et al.
From the Gamma book:
Component
- Declares the interface for object in the composition.
- Implements default behavior for the interface common to all classes, as appropriate.
- Declares an interface for accessing and managing its child components.
- Optionally defines an interface for accessing a component's parent in the recursive structure and implements it if that's appropriate.
Leaf
- Represents leaf objects in the composition. A leaf has no children.
- Defines behavior for primitive objects in the composition.
Composite
- Defines behavior for components having children.
- Stores child components.
- Implements child-related operations in the Component interface.
A House
will be a Component
. Garage
, Garden
and SwimmingPool
will be either a Leaf
or a Composite
depending on whether they are composed of child components or not.
Needless to say (?), these interfaces can many operations besides operation()
.
答案2
得分: 1
用“具有”比“是”的方式更好,这支持了您关于继承的说法。
public interface IFeature { ... }
public class Garage : IFeature
{
public Garage(string colour){ ... }
}
public class House
{
private readonly IList<IFeature> _features = new List<IFeature>();
public House() { ... }
public House(IList<IFeature> features) { _features = features; }
public IFeature AddFeature(IFeature feature)
{
_features.Add(feature);
return feature;
}
}
英文:
Better with "has-a" than "is-a", which supports your statement regarding inheritance.
public interface IFeature { ... }
public class Garage : IFeature
{
public Garage(string colour){ ... }
}
public class House
{
private readonly IList<IFeature> _features = new List<IFeature>();
public House() { ... }
public House(IList<IFeature> features) { _features = features; }
public IFeature AddFeature(IFeature feature)
{
_features.Add(feature);
return feature;
}
}
答案3
得分: 1
根据您的评论,您希望在运行时保存一组组件,并强制客户在使用特定组件之前确保已添加该组件。我不知道针对此设计的模式,但您可以简单地保存一个附加组件的字典,并通过类型进行查找:
public class House
{
private readonly Dictionary<Type, object> _components = new Dictionary<Type, object>();
public void AddComponent<T>([DisallowNull] T component) where T : class, IHouseComponent
{
_components.Add(typeof(T), component);
}
[return: MaybeNull]
public T GetComponent<T>() where T : class, IHouseComponent
{
return _components.TryGetValue(typeof(T), out var component) ? (T) component : null;
}
}
因此,当您有一个 House
和一个 Garage
时,可以执行以下操作:
House house;
Garage garage;
...
house.AddComponent(garage);
...
// 在其他地方
var garage = house.GetComponent<Garage>();
IHouseComponent
是一个标记接口,这样您必须在将其添加到 House
之前显式实现它(因此您不能只添加任何 object
)。
如果可能添加多个相同类型的组件,则在字典中保存它们的列表:
private readonly Dictionary<Type, List<object>> _components = ...
public void AddComponent<T>(...)
{
if (_components.TryGetValue(typeof(T), out var list))
{
list.Add(component);
}
else
{
_components.Add(typeof(T), new List<object> { component });
}
}
public IEnumerable<T> GetComponents<T>() ...
{
if (_components.TryGetValue(typeof(T), out var list))
{
return list.ToList();
}
else
{
return Enumerable.Empty<T>();
}
}
英文:
Based on your comment you want to hold a collection of components at runtime and force your clients to make sure that a given component is added before working with it. I'm not aware of a design pattern for that, but you can simply hold a dictionary of attached components and look them up by type:
public class House
{
private readonly Dictionary<Type, object> _components = new Dictionary<Type, object>();
public void AddComponent<T>([DisallowNull] T component) where T : class, IHouseComponent
{
_components.Add(typeof(T), component);
}
[return: MaybeNull]
public T GetComponent<T>() where T : class, IHouseComponent
{
return _components.TryGetValue(typeof(T), out var component) ? (T) component : null;
}
}
So when you have a house
and a garage
you can do:
House house;
Garage garage;
...
house.AddComponent(garage);
...
// somewhere else
var garage = house.GetComponent<Garage>();
IHouseComponent
is a marker interface so that you have to explicitly implement it before adding it to a House
(so you can't just add any object
).
If it's possible for multiple components of the same type to be added, just hold a list of them in the dictionary:
private readonly Dictionary<Type, List<object>> _components = ...
public void AddComponent<T>(...)
{
if (_components.TryGetValue(typeof(T), out var list)
{
list.Add(component);
}
else
{
_components.Add(typeof(T), new List<object>{ component });
}
}
public IEnumerable<T> GetComponents<T>() ...
{
if (_components.TryGetValue(typeof(T), out var list))
{
return list.ToList();
}
else
{
return Enumerable.Empty<T>();
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论