装饰器、包装器和适配器模式之间有啥区别?

Posted

技术标签:

【中文标题】装饰器、包装器和适配器模式之间有啥区别?【英文标题】:What are the differences between Decorator, Wrapper and Adapter patterns?装饰器、包装器和适配器模式之间有什么区别? 【发布时间】:2017-04-21 03:09:11 【问题描述】:

我觉得我已经多次使用这些模式系列,但是,对我来说很难看出它们之间的差异,因为它们的定义非常相似。基本上,它们似乎都是关于包装另一个或多个对象以用额外的东西扩展或包装它们的行为。

举个简单的例子,在存储库模式上实现缓存机制似乎就是这种情况。这是我可能会开始使用的快速示例C# 代码。

public interface IRepository 
  IEnumerable<T> GetItems<T>();


public class EntityFrameworkRepository : IRepository 
  ...


public class CachedRepository : IRepository 

  private IRepository _repository;
  private ICacheProvider _cache;

  public CachedRepository(IRepository repository, ICacheProvider cache) 
    this._repository = repository;
    this._cache = cache;
  

  public IEnumerable<T> GetItems<T>() 
    ...
  

例如,这些模式中的哪一种适用于这种情况?谁能简要说明一下理论和实践的区别?

【问题讨论】:

How do the Proxy, Decorator, Adapter, and Bridge Patterns differ?的可能重复 相关:***.com/questions/3489131/… 【参考方案1】:

理论上它们是相同的,只是intent 将一种模式与另一种模式区分开来:

装饰器:

通过使用具有相同接口的类包装对象来组合/添加功能

适配器:

允许您在没有已知接口实现的情况下包装对象 所以它坚持一个接口。关键是将一个界面“翻译”成另一个界面。

包装器:

从来没有听说过这是一种设计模式,但我想这只是上面的通用名称

您指定的示例我将归类为装饰器:CacheRepository decoratesIRepository 添加缓存功能。

【讨论】:

好的,我正在删除我的答案。 :) 我困惑的根源是“包装器”作为一个单独的模式,如果我没记错的话,我肯定在某个地方读过。与此同时,另一个人确认“包装器”是一种编码技术,它允许您实现例如装饰器模式。谢谢你们的澄清。 好东西!我从适配器上的@lexicore 答案中窃取了一些信息,供未来访问者使用。【参考方案2】:

程序员可能会编写一个 A 类,重点是保存另一个 B 类的对象。A 类将被称为 B 类的包装器。为什么 A 类包装 B 类?装饰或调整它。 装饰器和适配器是包装器。


假设 A 类被编写成通过调用 B 类对象的方法来实现 B 类的接口。然后它可以用来代替 B 类。除了它让程序员有机会在调用 B 类对象的方法之前或之后添加一些代码之外,这没有任何意义。这个版本的 A 类将被称为 B 类的装饰器装饰器在添加一些行为的同时保持界面不变。

interface ICatInterface 
  public void wakeUp();


class Cat implements ICatInterface 
  public void wakeUp() 
    System.out.println("I came. I saw. I napped.");
  


class YogaCat implements ICatInterface 

  private ICatInterface cat;

  public YogaCat(ICatInterface cat) 
    this.cat = cat;
  

  public void wakeUp() 
    System.out.println("[Stretch]"); // <- This is the decoration.
    cat.wakeUp();
  


请参阅this example,了解使用此模式在运行时组合具有不同行为的对象的更复杂方法。


现在想象一下,类 A 是这样编写的,它实现了一些接口 C,但主要是通过调用其类 B 对象的方法来实现的。这是一种将 B 类中可用的方法转换为接口 C 的方法。此版本的 A 类将被称为 B 类的适配器。就像您要为手机充电一样。有从墙壁或汽车电源到 USB 端口的适配器。 适配器将接口更改为其他接口,但不一定添加任何行为。

interface TakeDirectionsInterface 
  public void turnLeft();
  public void turnRight();
  public void go();
  public void stop();


class Driver 
  public enum TurnDirection
   
    CLOCKWISE, COUNTERCLOCKWISE;
  

  public enum FootPedal
   
    ACCELERATOR, BRAKE, CLUTCH;
  

  public void turnSteeringWheel(TurnDirection direction) 
    System.out.println("Turning the steering wheel " + direction.toString() + ".");
  

  public void pressPedal(FootPedal pedal) 
    System.out.println("Pressing the " + pedal.toString() + "pedal.");
  


class DriverAdapter implements TakeDirectionsInterface 

  private Driver driver;

  public DriverAdapter(Driver driver) 
    this.driver = driver;
  

  public void turnLeft()
    driver.turnSteeringWheel(Driver.TurnDirection.COUNTERCLOCKWISE);
  

  public void turnRight()
    driver.turnSteeringWheel(Driver.TurnDirection.CLOCKWISE);
  

  public void go()
    driver.pressPedal(Driver.FootPedal.ACCELERATOR);
  

  public void stop()
    driver.pressPedal(Driver.FootPedal.BRAKE);
  


【讨论】:

以上是关于装饰器、包装器和适配器模式之间有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

Python 装饰器和装饰器模式有啥区别?

设计模式 - 适配器模式与装饰器模式? [复制]

适配器模式和装饰器模式有什么区别?

代理模式、装饰者模式

图解设计模式

IO流的设计模式