带构造函数的开闭原理

Posted

技术标签:

【中文标题】带构造函数的开闭原理【英文标题】:Open-closed principle with constructor 【发布时间】:2016-12-30 21:45:25 【问题描述】:

学习“SOLID”原则我想知道如果我需要向类添加更多扩展,是否可以修改构造函数,例如。商业逻辑。

据我所知,修改构造函数似乎违反了“开闭”原则,但是如果我需要注入另一个类来执行某些逻辑怎么办?我如何在不修改构造函数的情况下做到这一点,一般来说,构造函数修改是否违反了“开闭”原则?

让我们考虑一个例子。

有一个界面

public interface ShopFactory 
    List<Discount> getDiscounts();
    List<Sale> getSales();

而且有一个实现(如果有人想将我的库添加为依赖项,可能还有其他实现)

public class CountableDefaultShopFactory implements ShopFactory 

    Counter discountsCounter;
    Counter salesCounter;

    public DefaultShopFactory(Counter discountsCounter, Counter salesCounter) 
        this.discountsCounter = discountsCounter;
        this.salesCounter = salesCounter;
    

    @Override
    List<Discount> getDiscounts() 
        discountsCounter.count();
        return Discount.defaultDiscounts();
    

    @Override
    List<Sale> getSales() 
        salesCounter.count();
        return Sale.defaultSales();
    


所以这很简单。 CountableDefaultShopFactory 实现 ShopFactory,覆盖两个方法并依赖于一些 Counter 对象,以计算每个方法被调用的次数。每个方法都使用静态方法返回一些数据。

现在假设我被要求再添加一个方法,这次我需要从某个存储中获取数据,并且有一项服务可以从该存储中提供一些数据。在这种情况下,我需要在我的类中注入此服务以执行操作。

它看起来像这样:

public class CountableDefaultShopFactory implements ShopFactory 

    Counter discountsCounter;
    Counter salesCounter;
    Counter couponsCounter;
    CouponDAO couponDAO;

    public DefaultShopFactory(Counter discountsCounter, Counter salesCounter, Counter couponsCounter, CouponDAO couponDAO) 
        this.discountsCounter = discountsCounter;
        this.salesCounter = salesCounter;
        this.couponsCounter = couponsCounter;
        this.couponDAO = couponDAO;
    

    @Override
    List<Discount> getDiscounts() 
        discountsCounter.count();
        return Discount.defaultDiscounts();
    

    @Override
    List<Sale> getSales() 
        salesCounter.count();
        return Sale.defaultSales();
    

    @Override
    List<Coupon> getCoupons() 
        couponsCounter.count();
        return couponDAO.getDefaultCoupons();
    


所以我不得不修改我的构造函数,再添加一个Counter 类和CouponDAO。没关系,我需要再添加一个名为couponsCounterCounter,因为这是ShopFactory 的可数实现。但是添加CouponDAO 对我来说并不好。

我想知道有没有更好的解决方案如何做到这一点?

【问题讨论】:

是什么造就了这些Factorys? 【参考方案1】:

是的,它违反了 Open Closed,但也违反了 SRP,因为您现在已经为班级提供了不止一个更改理由。

出现了一个新要求,您可以在不更改现有内容并添加所有仅由单个方法使用的新依赖项的情况下扩展代码。 (如果你不介意,我会放弃 Factory 后缀):

public interface CouponShop extends Shop 
    List<Coupon> getCoupons();


public class CountableCouponShop implements CouponShop 

    public CountableCouponShop(Shop shop, Counter couponsCounter, CouponDAO couponDAO) 
        //assign to fields
    

    @Override
    List<Discount> getDiscounts() 
        return shop.getDiscounts(); //just delegate to the old implementation of shop
    

    @Override
    List<Sale> getSales() 
        return shop.getSales();
    

    @Override
    List<Coupon> getCoupons() 
        couponsCounter.count();
        return couponDAO.getDefaultCoupons();
    

【讨论】:

感谢您的回答。您能否解释一下为什么它会导致 SRP 波动? 正如我所说,您现在已经为全班提供了不止一个改变的理由 我只看到一个原因,即增加了一种方法,其他的呢? 不,我的意思是一旦它既有旧代码又有新代码,那么有两个原因要改变。这些方法的不同依赖关系突出了这些方法的共同点。这也称为低内聚力。

以上是关于带构造函数的开闭原理的主要内容,如果未能解决你的问题,请参考以下文章

4装饰器生成器迭代器

针对不同过滤条件的开闭原理

默认构造函数嵌套带参构造函数

java怎么调用带参数构造函数

构造函数

构造函数