库、“注入工厂”和扩展库的最佳实践

Posted

技术标签:

【中文标题】库、“注入工厂”和扩展库的最佳实践【英文标题】:Library, “Injecting factory” and best practices for extending a library 【发布时间】:2021-09-12 19:29:07 【问题描述】:

我使用了一个需要修补的库。我需要分叉它,因为没有使用工厂设计模式。

库具有这样的结构:X 类包含对其他类的引用、对其他类的引用以及更多层。类层次结构是“树状”结构。

我寻找重构的最佳方式——足够灵活以防止人们分叉它。我找不到任何关于该问题的最佳实践。

多年来,我使用“注入工厂”来解决这个问题——工厂模式在工厂方法中注入父对象 (DI)。我找不到任何关于这种方法的文档,我需要一些反馈(例如理论或可能的问题)。

我用汽车的例子来描述它:

汽车有 CarInterior CarInterior 有里程表

问题 - 无法创建自定义对象,尤其是里程表。

class Car 
  CarInterior interior;
  public Car() 
    interior = new CarInterior();
  

class CarInterior 
  Odometer odo;
  public CasInterior()
    odo = new Odomether();
  

class Odometer 
  public Odometer()

仅使用简单工厂方法模式的按书解决方案(扩展性有限)

class Car 
  CarInterior interior;
  public Car(CarFactory factory) 
    interior = createInterior();
  
  CarInterior createInterior()  return new CarInterior(); ;

class CasInterior 
  Odometer odo;
  public CarInterior()
    odo = createOdometer();
  
  CarInterior createOdometer() 
    return new Odomether();
  

这种方法的主要问题

如果工厂方法需要参数,则该更改可能会给 lib 用户带来麻烦。因为扩展类应该改变方法定义。

小问题

如果我需要不同的里程表,我应该同时扩展 Car 和 CarInterior 我需要 fork 的库的“级别”很少,因此这意味着在我设法调用工厂方法之前有很多级别的额外对象。

可能的业务请求

里程表类的可能扩展#1:KM 或 Miles

汽车对象应该有targetCountry。如果是在法国,则应使用公制单位。如果在美国 - 英里。 该业务请求可以通过这种方式实现:

(重大更改)工厂方法 createOdometer() 获取参数:createOdometer(OdoUnits) (重大更改)工厂方法 createInterior() 获取参数:createInterior(OdoUnits) 或 createInterior(Country) 如果级别更多(我的情况),则需要进行更多更改

里程表类的可能扩展#2:里程表值范围

0-220 公里/小时 0-300 公里/小时 等

里程表类的可能扩展#3:里程表颜色应与汽车颜色相同

如果我们使用相同的方法,我们应该在方法中引入更多参数。以及更多“代理”功能。

问题

那么解决这个问题的最佳做法是什么?当新需求出现时,我们如何避免/减少方法定义的更改?

【问题讨论】:

【参考方案1】:

《注塑厂》

工厂方法需要一个额外的参数——父对象。 里程表获取其工厂,获取 Car 对象并请求所有需要的数据以适应“汽车规格”

代码:

class CarFactory 
  CarInterior createInterior(Car car)  return new CarInterior(car); 
  Odometer createOdometer(CarInterior interior) return new Odometer(interior); ;

class Car 
  CarFactory factory;
  CarInterior interior;
  public Car(CarFactory factory) 
    this.factory = factory;
    interior = factory.createInterior(this);
  
  CarFactory getFactory() return factory; ;

class CarInterior 
  Car car;
  Odometer odo;
  public CarInterior(Car car)
    this.car = car;
    CarFactory factory = car.getFactory();
    odo = factory.createOdometer( this );
  

class Odometer 
  public Odometer(CarInterior interior) 
    Car car = interior.getCar();
    OdoUnits odoUnits = car.getTargetCountry().getUnits();
    int maxEngineSpeed = car.getEngine().getTopSpeed;
    Color color = car.getColor();
    if (!car.isOptionColorOdometer())
      color = DEFAULT_COLOR; 
    // etc
  

【讨论】:

以上是关于库、“注入工厂”和扩展库的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

不使用支持库的 Android 4.0、4.1 (<4.2) 中嵌套片段的最佳实践

最佳实践:扩展或覆盖 Android 库项目类

21条最佳实践,全面保障 GitHub 使用安全

Closure Compiler - JavaScript 库项目的最佳实践?

前端基础设施怎么搞?看腾讯TDesign跨技术栈组件库的最佳实践

在 .Net 中使用扩展方法的最佳实践是啥?