继承和复用

目录

背景设计的演化待重构的代码用继承消除重复用扩展类(Mixin)消除重复Ruby的鸭子类型 + Mixin的实现备注

背景返回目录

今天上午和以为朋友聊了一个设计问题:如何消除仓库相关的单据的Repository中的重复逻辑?如:入库单Repository和出库单Repository之间的重复。可以有很多方式消除重复,在不同级别消除重复,如:继承、组合、掺入、帮助类、帮助方法。本文只说出我的观点:不要为了复用而使用继承

设计的演化返回目录

下面我会演示:待重构的重复代码-》用继承消除重复-》用扩展类(Mixin)消除重复-》Ruby的鸭子类型 + Mixin的实现(元编程可以更牛叉,有机会再说)。

待重构的代码返回目录

注意:出库单仓储和入库单仓储的“根据编号获取单据”重复了。

类图

代码

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Linq.Expressions;
 7 
 8 namespace CSharpStudy.MixinStudy.V1
 9 {
10     class Aggregate { }
11 
12     interface IRepository<T> where T : Aggregate
13     {
14         IEnumerable<T> Where(Expression<Func<T, bool>> condition);
15     }
16 
17     class Repository<T> : IRepository<T>
18         where T : Aggregate
19     {
20         public IEnumerable<T> Where(Expression<Func<T, bool>> condition)
21         {
22             throw new NotImplementedException();
23         }
24     }
25 
26     class 入库单 : Aggregate
27     {
28         public string 单据编号 { get; set; }
29     }
30 
31     class 出库单 : Aggregate
32     {
复制代码

用继承消除重复返回目录

当我看到上面的重复代码的时候,第一印象是引入两个基类:仓库单据基类和仓库单据仓储基类。

类图

代码

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Linq.Expressions;
 7 
 8 namespace CSharpStudy.MixinStudy.V2
 9 {
10     class Aggregate { }
11 
12     interface IRepository<T> where T : Aggregate
13     {
14         IEnumerable<T> Where(Expression<Func<T, bool>> condition);
15     }
16 
17     class Repository<T> : IRepository<T>
18         where T : Aggregate
19     {
20         public IEnumerable<T> Where(Expression<Func<T, bool>> condition)
21         {
22             throw new NotImplementedException();
23         }
24     }
25 
26     class 仓库单据基类 : Aggregate
27     {
28         public string 单据编号 { get; set; }
29     }
30 
31     class 入库单 : 仓库单据基类 { }
32 
33     class 出库单 : 仓库单据基类 { }
34 
35     class 仓库单据仓储基类<T> : Repository<T>
36         where T : 仓库单据基类
37     {
38         public IEnumerable<T> 根据编号获取单据(string 单据编号)
39         {
40             return this.Where(x => x.单据编号 == 单据编号);
41         }
42     }
43 
44     class 入库单仓储 : 仓库单据仓储基类<入库单> { }
45 
46     class 出库单仓储 : 仓库单据仓储基类<出库单> { }
47 }
复制代码

用扩展类(Mixin)消除重复返回目录

我对了吗?没有多态,只是为了复用就引入继承,是否合理呢?

类图

代码

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Linq.Expressions;
 7 
 8 namespace CSharpStudy.MixinStudy.V3
 9 {
10     class Aggregate { }
11 
12     interface IRepository<T> where T : Aggregate
13     {
14         IEnumerable<T> Where(Expression<Func<T, bool>> condition);
15     }
16 
17     class Repository<T> : IRepository<T>
18         where T : Aggregate
19     {
20         public IEnumerable<T> Where(Expression<Func<T, bool>> condition)
21         {
22             throw new NotImplementedException();
23         }
24     }
25 
26     class 仓库单据基类 : Aggregate
27     {
28         public string 单据编号 { get; set; }
29     }
30 
31     class 入库单 : 仓库单据基类 { }
32 
33     class 出库单 : 仓库单据基类 { }
34 
35     static class 仓库单据基类仓储扩展
36     {
37         public static IEnumerable<T> 根据编号获取单据<T>(this IRepository<T> that, string 单据编号)
38             where T : 仓库单据基类
39         {
40             return that.Where(x => x.单据编号 == 单据编号);
41         }
42     }
43 }
复制代码

Ruby的鸭子类型 + Mixin的实现返回目录

代码

复制代码
 1 # coding: utf-8
 2 
 3 class Aggregate
 4 end
 5 
 6 class Repository
 7     def Where(condition)
 8     end
 9 end
10 
11 class C仓库单据基类 < Repository
12     attr_accessor :单据编号
13 end
14 
15 class C入库单 < C仓库单据基类
16 end
17 
18 class C出库单 < C仓库单据基类
19 end
20 
21 module C仓库单据基类仓储扩展
22     def 根据编号获取单据(单据编号)
23         return self.Where({:单据编号 => 单据编号})
24     end
25 end
26 
27 class C入库单仓储 < Repository
28     include C仓库单据基类仓储扩展
29 end
30 
31 class C出库单仓储 < Repository
32     include C仓库单据基类仓储扩展
33 end
复制代码

Ruby正统的支持了Mixin,鸭子类型天生具备泛型的特点,比泛型强大,元编程更是牛叉(本文没有体现)。

备注返回目录

 做一件事如果只有一个选择,就说明 有问题了,多思考几个方案,折中后考虑一个方案。

原文地址:https://www.cnblogs.com/Leo_wl/p/3277783.html