今天更新一個版本,主要處理上一版原先寫法問題:
XML存取實作IBlogService介面,MSSQL存取也實作IBlogService介面,導致
"重複編寫相同方法"
GetPosts都是從cache讀取資料,實作代碼也一樣。
假如後面新增一個SQLite讀取方式,代表程式要重複三次一樣的代碼,造成之後不好統一維護問題
。
public interface IBlogService
{
//略...
Task<IEnumerable<Post>> GetPosts(int count, int skip = 0);
//略...
}
public class FileBlogService : IBlogService{
//略...
public virtual Task<IEnumerable<Post>> GetPosts(int count, int skip = 0)
{
//略...
var posts = _cache
.Where(p => p.PubDate <= DateTime.UtcNow && (p.IsPublished || isAdmin))
.Skip(skip)
.Take(count);
//略...
}
//略...
}
public class MSSqlBlogService : IBlogService{
//略...
public virtual Task<IEnumerable<Post>> GetPosts(int count, int skip = 0)
{
//略...
var posts = _cache
.Where(p => p.PubDate <= DateTime.UtcNow && (p.IsPublished || isAdmin))
.Skip(skip)
.Take(count);
//略...
}
//略...
}
避免重複方法可以使用繼承抽象類別
1.新增一個抽象類別InMemoryBlogServiceBase
實作IBlogService介面
2.把GetPosts實作代碼寫在該類別
3.接著FileBlogService跟MSSqlBlogService的GetPosts方法都刪除
4.FileBlogService跟MSSqlBlogService繼承該類別
public interface IBlogService
{
//略...
Task<IEnumerable<Post>> GetPosts(int count, int skip = 0);
//略...
}
public abstract class InMemoryBlogServiceBase : IBlogService{
//略...
public virtual Task<IEnumerable<Post>> GetPosts(int count, int skip = 0)
{
//略...
var posts = _cache
.Where(p => p.PubDate <= DateTime.UtcNow && (p.IsPublished || isAdmin))
.Skip(skip)
.Take(count);
//略...
}
//略...
}
public class FileBlogService : InMemoryBlogServiceBase{
//略...
}
public class MSSqlBlogService : InMemoryBlogServiceBase{
//略...
}
聰明的讀者這時候會想到"不一定需要抽象類別",繼承
普通類別
也可以達到同樣效果
是的,但是這對同樣實作代碼的方法有用而已,假如有不同行為又必須實作的方法就沒有約束效果
。
FileBlogService跟MSSqlBlogService在保存資料都需要使用SavePost方法,但是有不同的行為:一個保存在XML,一個保存在DB。
這時候可以在InMemoryBlogServiceBase
建立一個抽象方法SavePost,要求繼承的類別一定要實作方法
,否則無法編譯(如圖)。
代碼:
public interface IBlogService
{
//略...
Task SavePost(Post post);
//略...
}
public abstract class InMemoryBlogServiceBase : IBlogService{
//略...
public abstract Task SavePost(Post post);
//略...
}
public class FileBlogService : InMemoryBlogServiceBase{
public override async Task SavePost(Post post){
//保存資料到XML
}
}
public class MSSqlBlogService : InMemoryBlogServiceBase{
public override async Task SavePost(Post post){
//保存資料到DB
}
}
做完以上的動作後,當前端更新文章資料傳到BlogController
藉著IBlogService介面物件呼叫SavePost
方法
public class BlogController : Controller
{
private readonly IBlogService _blog;
public BlogController(IBlogService blog, IOptionsSnapshot<BlogSettings> settings, WebManifest manifest)
{
_blog = blog;
}
public async Task<IActionResult> UpdatePost(Post post)
{
await _blog.SavePost(existing);
}
}
只要替換ConfigureServices方法的依賴注射類別:
達到改一行代碼,就可以替換整個存取邏輯。
services.AddSingleton<IBlogService, 想要存取方式的類別>();