英文:
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>();
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。



评论