如何解决在运行时采用新功能的对象的设计模式?
假设我有一个House
类。
我想为自己的房屋添加规格,例如Garage
,SwimmingPool
或Garden
,每种规格都有自己的一套新方法。
如果我使用继承,则将有子类HouseWithGarage
,HouseWithSwimmingPool
和HouseWithGarden
。但是,如果我想同时拥有一个带车库和花园的物品怎么办?如果以后我想在运行时将游泳池添加到同一对象怎么办?
显然,继承在这里不能很好地工作。您知道适合这种问题的任何设计模式吗?
解决方法
最能描述您所寻找内容的模式是复合模式,在Gamma等人的“设计模式”中进行了描述。
摘自Gamma书:
组件
- 在合成中声明对象的接口。
- 根据情况为所有类通用的接口实现默认行为。
- 声明用于访问和管理其子组件的接口。
- (可选)定义一个用于访问递归结构中组件父级的接口,并在适当时实现该接口。
叶子
- 表示合成中的叶对象。一片叶子没有孩子。
- 定义合成中原始对象的行为。
复合
- 定义具有子级的组件的行为。
- 存储子组件。
- 在Component界面中实现与孩子相关的操作。
House
将是Component
。根据它们是否由子组件组成,Garage
,Garden
和SwimmingPool
将是Leaf
或Composite
。
不用说(?),除了operation()
之外,这些接口还可以许多操作。
用“ has-a”比“ is-a”更好,这支持您有关继承的声明。
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;
}
}
,
根据您的评论,您希望在运行时保留一组组件,并强制您的客户端确保在使用给定组件之前已添加该组件。我不知道该使用哪种设计模式,但是您只需持有一个附加组件的字典,然后按类型查找它们:
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);
...
// somewhere else
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>();
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。