在运行时假设新特性的对象设计模式?

huangapple go评论77阅读模式
英文:

Design pattern for object assuming new features at runtime?

问题

假设我有一个名为 House 的类。

我想要给我的房屋添加规格,比如一个 Garage,一个 SwimmingPool 或者一个 Garden,每个规格都带有一组自己的新方法。

如果我使用继承,我会有子类 HouseWithGarageHouseWithSwimmingPoolHouseWithGarden。但如果我希望一个对象同时有一个车库和一个花园呢?如果以后我想在运行时为同一个对象添加一个游泳池呢?

显然继承在这里不适用。您是否知道适用于这种问题的任何设计模式?

英文:

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(组件)

  1. 声明组合中对象的接口。
  2. 根据需要,为所有类共有的接口实现默认行为。
  3. 声明访问和管理其子组件的接口。
  4. 如果适用,还可以为访问组件递归结构中的父组件定义接口,并在需要时实现该接口。

Leaf(叶节点)

  1. 代表组合中的叶对象。叶节点没有子节点。
  2. 为组合中的原始对象定义行为。

Composite(复合对象)

  1. 为具有子节点的组件定义行为。
  2. 存储子组件。
  3. 在组件接口中实现与子节点相关的操作。

House 将是一个 Component(组件)。GarageGardenSwimmingPool 将根据它们是否由子组件组成而分别是 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

  1. Declares the interface for object in the composition.
  2. Implements default behavior for the interface common to all classes, as appropriate.
  3. Declares an interface for accessing and managing its child components.
  4. Optionally defines an interface for accessing a component's parent in the recursive structure and implements it if that's appropriate.

Leaf

  1. Represents leaf objects in the composition. A leaf has no children.
  2. Defines behavior for primitive objects in the composition.

Composite

  1. Defines behavior for components having children.
  2. Stores child components.
  3. 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&lt;IFeature&gt; _features = new List&lt;IFeature&gt;();

  public House() { ... }

  public House(IList&lt;IFeature&gt; 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&lt;Type, object&gt; _components = new Dictionary&lt;Type, object&gt;();

    public void AddComponent&lt;T&gt;([DisallowNull] T component) where T : class, IHouseComponent
    {
        _components.Add(typeof(T), component);
    }

    [return: MaybeNull]
    public T GetComponent&lt;T&gt;() 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&lt;Garage&gt;();

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&lt;Type, List&lt;object&gt;&gt; _components = ...

public void AddComponent&lt;T&gt;(...)
{
    if (_components.TryGetValue(typeof(T), out var list)
    {
        list.Add(component);
    }
    else
    {
        _components.Add(typeof(T), new List&lt;object&gt;{ component });
    }
}

public IEnumerable&lt;T&gt; GetComponents&lt;T&gt;() ...
{
    if (_components.TryGetValue(typeof(T), out var list))
    {
        return list.ToList();
    }
    else
    {
        return Enumerable.Empty&lt;T&gt;();
    }
}

huangapple
  • 本文由 发表于 2020年8月15日 18:56:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/63425241.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定