ในรูปแบบการออกแบบ OOP ความแตกต่างระหว่างรูปแบบพื้นที่เก็บข้อมูลและชั้นบริการคืออะไร
ฉันกำลังทำงานกับแอพ ASP.NET MVC 3 และพยายามที่จะเข้าใจรูปแบบการออกแบบเหล่านี้ แต่สมองของฉันไม่เข้าใจเลย ... ยัง !!
ในรูปแบบการออกแบบ OOP ความแตกต่างระหว่างรูปแบบพื้นที่เก็บข้อมูลและชั้นบริการคืออะไร
ฉันกำลังทำงานกับแอพ ASP.NET MVC 3 และพยายามที่จะเข้าใจรูปแบบการออกแบบเหล่านี้ แต่สมองของฉันไม่เข้าใจเลย ... ยัง !!
คำตอบ:
Repository Layer ให้คุณเพิ่มระดับของ abstraction ผ่าน data access แทนที่จะเขียน
var context = new DatabaseContext();
return CreateObjectQuery<Type>().Where(t => t.ID == param).First();
ในการรับไอเท็มเดี่ยวจากฐานข้อมูลคุณใช้อินเตอร์เฟสที่เก็บ
public interface IRepository<T>
{
IQueryable<T> List();
bool Create(T item);
bool Delete(int id);
T Get(int id);
bool SaveChanges();
}
Get(id)
และโทร เลเยอร์ที่เก็บข้อมูลจะเปิดเผยการดำเนินการCRUDขั้นพื้นฐาน
Service layer แสดงตรรกะทางธุรกิจซึ่งใช้ที่เก็บ ตัวอย่างบริการอาจมีลักษณะดังนี้:
public interface IUserService
{
User GetByUserName(string userName);
string GetUserNameByEmail(string email);
bool EditBasicUserData(User user);
User GetUserByID(int id);
bool DeleteUser(int id);
IQueryable<User> ListUsers();
bool ChangePassword(string userName, string newPassword);
bool SendPasswordReminder(string userName);
bool RegisterNewUser(RegisterNewUserModel model);
}
ขณะที่List()
เมธอดของที่เก็บส่งคืนผู้ใช้ทั้งหมด แต่ListUsers()
IUserService สามารถส่งคืนได้เฉพาะผู้ใช้ที่มีสิทธิ์เข้าถึง
ใน ASP.NET MVC + EF + SQL SERVER ฉันมีกระบวนการสื่อสารนี้:
Views <- Controllers -> Service layer -> Repository layer -> EF -> SQL Server
Service layer -> Repository layer -> EFส่วนนี้ใช้กับรุ่นต่างๆ
Views <- Controllers -> เลเยอร์บริการส่วนนี้ทำงานกับรุ่นที่มีมุมมอง
แก้ไข:
ตัวอย่างของการไหลสำหรับ / คำสั่งซื้อ / ByClient / 5 (เราต้องการดูคำสั่งซื้อสำหรับลูกค้าที่เฉพาะเจาะจง):
public class OrderController
{
private IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService; // injected by IOC container
}
public ActionResult ByClient(int id)
{
var model = _orderService.GetByClient(id);
return View(model);
}
}
นี่คืออินเทอร์เฟซสำหรับบริการสั่งซื้อ:
public interface IOrderService
{
OrdersByClientViewModel GetByClient(int id);
}
อินเตอร์เฟสนี้ส่งคืนโมเดลมุมมอง:
public class OrdersByClientViewModel
{
CientViewModel Client { get; set; } //instead of ClientView, in simple project EF Client class could be used
IEnumerable<OrderViewModel> Orders { get; set; }
}
นี่คือการใช้อินเตอร์เฟส มันใช้คลาสโมเดลและที่เก็บเพื่อสร้างมุมมองโมเดล:
public class OrderService : IOrderService
{
IRepository<Client> _clientRepository;
public OrderService(IRepository<Client> clientRepository)
{
_clientRepository = clientRepository; //injected
}
public OrdersByClientViewModel GetByClient(int id)
{
return _clientRepository.Get(id).Select(c =>
new OrdersByClientViewModel
{
Cient = new ClientViewModel { ...init with values from c...}
Orders = c.Orders.Select(o => new OrderViewModel { ...init with values from o...}
}
);
}
}
IRepository<>
ไว้GenericRepository<>
ในไลบรารี IOC ของคุณ คำตอบนี้เก่ามาก UnitOfWork
ผมคิดว่าทางออกที่ดีที่สุดคือการรวมที่เก็บทั้งหมดในระดับหนึ่งที่เรียกว่า SaveChanges
มันควรจะมีพื้นที่เก็บข้อมูลของทุกชนิดและวิธีการหนึ่งที่เรียกว่า ที่เก็บทั้งหมดควรแบ่งปันบริบทของ EF หนึ่งบริบท
ในฐานะที่เป็น Carnotaurus กล่าวว่าพื้นที่เก็บข้อมูลมีหน้าที่รับผิดชอบในการทำแผนที่ข้อมูลของคุณจากรูปแบบการจัดเก็บไปยังวัตถุทางธุรกิจของคุณ ควรจัดการทั้งวิธีการอ่านและเขียนข้อมูล (ลบอัปเดตด้วย) จากและไปยังที่เก็บข้อมูล
วัตถุประสงค์ของเลเยอร์บริการในอีกทางหนึ่งคือการห่อหุ้มตรรกะทางธุรกิจไว้ในที่เดียวเพื่อส่งเสริมการใช้ซ้ำรหัสและการแยกข้อกังวล สิ่งนี้มักจะมีความหมายสำหรับฉันในทางปฏิบัติเมื่อสร้างไซต์ MVC ของ Asp.net คือฉันมีโครงสร้างนี้
[คอนโทรลเลอร์] โทร [บริการ (s)] ที่โทร [ที่เก็บ (IES)]
หลักการหนึ่งที่ฉันพบว่ามีประโยชน์คือการทำให้ตรรกะมีค่าน้อยที่สุดในคอนโทรลเลอร์และที่เก็บ
ในตัวควบคุมมันเป็นเพราะมันช่วยให้ฉันแห้ง เป็นเรื่องธรรมดามากที่ฉันต้องใช้ตัวกรองหรือลอจิกเดียวกันที่อื่นและถ้าฉันวางไว้ในตัวควบคุมฉันไม่สามารถนำมาใช้ซ้ำได้
ในที่เก็บเป็นเพราะฉันต้องการที่จะสามารถแทนที่ที่เก็บข้อมูลของฉัน (หรือ ORM) เมื่อสิ่งที่ดีกว่ามาพร้อม และถ้าฉันมีตรรกะในที่เก็บฉันต้องเขียนตรรกะนี้ใหม่เมื่อฉันเปลี่ยนที่เก็บ หากที่เก็บของฉันส่งคืน IQueryable เท่านั้นและบริการทำการกรองในอีกทางหนึ่งฉันจะต้องเปลี่ยนการแมปเท่านั้น
ตัวอย่างเช่นเมื่อเร็ว ๆ นี้ฉันได้แทนที่ที่เก็บ Linq-To-Sql หลายแห่งของฉันด้วย EF4 และที่ที่ฉันยังคงยึดมั่นกับหลักการนี้สามารถเปลี่ยนได้ภายในไม่กี่นาที ที่ฉันมีเหตุผลบางอย่างมันเป็นเรื่องของชั่วโมงแทน
onBeforeBuildBrowseQuery
และสามารถใช้ตัวสร้างแบบสอบถามเพื่อแก้ไขแบบสอบถาม
คำตอบที่ยอมรับ (และเพิ่มขึ้นหลายร้อยครั้ง) มีข้อบกพร่องที่สำคัญ ฉันต้องการที่จะชี้ให้เห็นในความคิดเห็น แต่มันก็จะถูกฝังอยู่ที่นั่นในบางสิ่ง 30 ความเห็นดังนั้นชี้ไปที่นี่
ฉันเข้าซื้อแอปพลิเคชันระดับองค์กรซึ่งสร้างขึ้นด้วยวิธีนี้และปฏิกิริยาเริ่มต้นของฉันคือWTH ? ViewModels ในชั้นบริการหรือไม่ ฉันไม่ต้องการเปลี่ยนการประชุมเพราะมีการพัฒนามาหลายปีฉันจึงกลับไปดู ViewModels ต่อไป เด็กชายมันกลายเป็นฝันร้ายเมื่อเราเริ่มใช้ WPF พวกเรา (ทีมงาน devs) มักจะพูดว่า: ViewModel ตัวไหน? ของจริง (ของที่เราเขียนสำหรับ WPF) หรือบริการหนึ่ง พวกเขาเขียนขึ้นสำหรับเว็บแอปพลิเคชันและยังมีการตั้งค่าสถานะIsReadOnlyเพื่อปิดการใช้งานการแก้ไขใน UI เมเจอร์ข้อบกพร่องที่สำคัญและทั้งหมดเพราะหนึ่งคำ: ViewModel !!
ก่อนที่คุณจะทำผิดพลาดต่อไปนี้เป็นเหตุผลเพิ่มเติมบางส่วนนอกเหนือจากเรื่องราวของฉันด้านบน:
การคืน ViewModel จากเลเยอร์บริการเป็นสิ่งที่ไม่ใหญ่มาก นั่นเหมือนการพูดว่า:
หากคุณต้องการใช้บริการเหล่านี้คุณควรใช้ MVVM และนี่คือ ViewModel ที่คุณต้องใช้ อุ๊ย!
บริการต่าง ๆ กำลังตั้งสมมติฐานว่าพวกเขาจะแสดงใน UI ที่ใดที่หนึ่ง จะเกิดอะไรขึ้นหากแอปพลิเคชันที่ไม่ใช่ UI ใช้เช่นบริการเว็บหรือบริการ windows
นั่นไม่ใช่แม้แต่ ViewModel จริง ViewModel จริงมีความสามารถในการสังเกตการณ์คำสั่ง ฯลฯ นั่นเป็นเพียง POCO ที่มีชื่อไม่ดี (ดูเรื่องราวของฉันด้านบนเพราะเหตุใดชื่อจึงสำคัญ)
แอปพลิเคชั่นที่ใช้งานได้ดีกว่าจะเป็นเลเยอร์การนำเสนอ (ใช้ ViewModels โดยเลเยอร์นี้) และเข้าใจ C # ได้ดียิ่งขึ้น อุ๊ย!
โปรดอย่าทำอย่างนั้น!
โดยปกติที่เก็บจะถูกใช้เป็นโครงยกพื้นเพื่อเติมเอนทิตีของคุณ - ชั้นบริการจะออกไปข้างนอกและส่งคำขอ ดูเหมือนว่าคุณจะวางที่เก็บไว้ใต้เลเยอร์บริการของคุณ
ชั้นเก็บข้อมูลถูกนำมาใช้ในการเข้าถึงฐานข้อมูลและช่วยในการขยายการดำเนินงาน CRUD บนฐานข้อมูล ในขณะที่ชั้นบริการประกอบด้วยตรรกะทางธุรกิจของแอปพลิเคชันและอาจใช้เลเยอร์พื้นที่เก็บข้อมูลเพื่อใช้ตรรกะบางอย่างที่เกี่ยวข้องกับฐานข้อมูล ในแอปพลิเคชันจะเป็นการดีกว่าถ้ามีเลเยอร์ที่เก็บแยกต่างหากและเลเยอร์บริการ การมีที่เก็บแยกต่างหากและเลเยอร์บริการทำให้รหัสเป็นแบบแยกส่วนและแยกฐานข้อมูลออกจากตรรกะทางธุรกิจ