Active Record通常用在MVC或者MVVM模式中的M,也就是Model层,它将对象的业务层和持久化层封装在一起,每一个实例对应数据库表中的一行,每一个字段对应这个数据库表的中列。同时也包含数据库操作的CRUD操作。在一些不复杂的业务逻辑中,这种模式大大的提高了开发效率,在Ruby on Rails框架中广泛使用。但是这种设计模式违反了Single Responsibility Principle原则,将业务层和持久化层耦合在一起,如果更换数据库,所有的的Model都需要修改,而且还不利于编写单元测试。
11 goto语句是邪恶的吗?你或许听过一篇由Edsger Dijkstra写的著名论文 Go To Statement Considered Harmful,在这篇论文中他批评了goto语句,并且推崇结构化编程。 使用goto通常非常有争议,甚至Dijkstra这篇文章也被批评了,诸如'GOTO Considered Harmful' Considered Harmful,那么你的观点是怎样的?
在程序开发中,程序代码的流程称为 Program ,程序在实际运行的流程称为 Process ,两者的差异越小越能容易掌控这个程序。假设一个程序是顺序执行的,也就是说只有赋值语句,那么 Program 的索引和 Process 的索引是一致的,同样对于条件语句程序也是同样如此。
但是如果程序包含了子过程 Procedure,那么Program 的索引和 Process 的索引开始不一致了,因为每一个过程内部也包含各自的Program和运行的时候的Processs;对于循环语句,从某种程度上来讲也是多余的,因为都可以用递归来表达。但是由于我们的思维方式更加熟悉归纳模式,循环语句是值得保留的,每次进入循环,运行时的动态索引发生内置嵌套,所以变得复杂起来;对于GOTO语句,则完全放弃了动态运行时候的坐标,这个给程序掌控带来巨大的灾难。
puts 'What is your name?'
name = gets
process_name(name)
puts 'What is your quest?'
quest = gets
process_quest(quest)
require 'tk'
root = TkRoot.new()
name_label = TkLabel.new() {text "What is Your Name?"}
name_label.pack
name = TkEntry.new(root).pack
name.bind("FocusOut") {process_name(name)}
quest_label = TkLabel.new() {text "What is Your Quest?"}
quest_label.pack
quest = TkEntry.new(root).pack
quest.bind("FocusOut") {process_quest(quest)}
Tk.mainloop()
public class Customer {
public string FirstName { get; init; }
public string SecondName { get; init; }
public Wallet Wallet { get; init; }
}
public class Wallet {
public double Balance { get; set; }
public void AddMoney(double deposit) => this.Balance += deposit;
public void SubtractMoney(double debit) => this.Balance -= debit;
}
public class Paperboy {
public void Pay(Customer customer, double payment)
{
Wallet wallet = customer.Wallet;
if (wallet.Balance > payment)
{
wallet.SubtractMoney(payment);
}
}
}
public class Customer
{
public string FirstName { get; init; }
public string SecondName { get; init; }
- public Wallet Wallet { get; init; }
+ public Wallet Wallet { private get; init; }
+ public void Pay(double payment)
+ {
+ if (Wallet.Balance > payment)
+ {
+ Wallet.SubtractMoney(payment);
+ }
+ else
+ {
+ //money not enough
+ }
+ }
}
// interface
type Option interface {
GetValue() interface{}
IsNull() bool
}
// `Some` struct
type Some struct {
val interface{}
}
func (s *Some) GetValue() interface{}{
return s.val
}
func (s *Some) IsNull() bool {
return false
}
// `None` struct
type None struct{
}
func (n *None) GetValue() interface{}{
return nil
}
func (n *None) IsNull() bool {
return true
}
class Stack extends ArrayList {
public void push(Object value) { … }
public Object pop() { … }
}
class CustomGroup extends ArrayList<Customer> {
//....
}
package animal
type dog struct {
name string
}
var instance *dog
var mux sync.Mux
func Instance() *dog {
if instance == nil {
mux.Lock()
defer mux.Unlock()
//double check
if instance == nil {
instance = new(dog)
}
}
return instance
}
package animal
type dog struct {
name string
}
var Dog *dog
func init(){
if Dog == nil {
Dog = new(dog)
}
}
public int Sum(List<int> arr)
{
int sum = 0;
foreach(var elem in arr)
{
sum += elem;
}
return sum;
}
- public int Sum(List<int> arr)
+ public int Sum(IEnumberable<int> arr)
{
int sum = 0;
foreach(var elem in arr)
{
sum += elem;
}
return sum;
}
public FileStream Read(string filePath)
{
return new FileStream(filePath, FileMode.Read);
}
- public FileStream Read(string filePath)
+ public Stream Read(string filePath)
{
return new FileStream(filePath, FileMode.Read);
}
// 违反数据抽象:直接暴露内部实现细节
public class ShoppingCart
{
// 直接暴露内部数据结构
public List<Product> Items = new List<Product>();
public decimal GetTotal()
{
decimal total = 0;
foreach (var item in Items)
{
total += item.Price * item.Quantity;
}
return total;
}
}
// 客户端代码直接依赖于List<Product>的实现
public class OrderProcessor
{
public void ProcessOrder(ShoppingCart cart)
{
// 客户端直接操作内部数据结构
for (int i = 0; i < cart.Items.Count; i++)
{
// 直接使用List的索引访问
Console.WriteLine($"Processing: {cart.Items[i].Name}");
}
// 直接修改内部状态
cart.Items.Clear();
}
}
// 遵循数据抽象:隐藏实现细节,提供抽象接口
public class ShoppingCart
{
// 私有化内部数据结构
private readonly List<Product> _items = new List<Product>();
// 只读属性,返回副本或只读集合
public IReadOnlyCollection<Product> Items => _items.AsReadOnly();
public int ItemCount => _items.Count;
public void AddItem(Product product)
{
var existing = _items.FirstOrDefault(p => p.Id == product.Id);
if (existing != null)
{
existing.Quantity += product.Quantity;
}
else
{
_items.Add(product);
}
}
public bool RemoveItem(int productId)
{
var item = _items.FirstOrDefault(p => p.Id == productId);
if (item != null)
{
return _items.Remove(item);
}
return false;
}
public void Clear()
{
_items.Clear();
}
public decimal GetTotal()
{
return _items.Sum(item => item.Price * item.Quantity);
}
}
// 客户端代码通过抽象接口操作
public class OrderProcessor
{
public void ProcessOrder(ShoppingCart cart)
{
// 通过抽象接口遍历
foreach (var item in cart.Items)
{
Console.WriteLine($"Processing: {item.Name}");
}
// 通过方法操作,而不是直接修改内部状态
cart.Clear();
}
}
public class UserService
{
public void CreateUser(string email, string password)
{
// 重复的邮箱验证逻辑
if (string.IsNullOrEmpty(email))
throw new ArgumentException("Email cannot be empty");
if (!email.Contains("@") || !email.Contains("."))
throw new ArgumentException("Invalid email format");
if (email.Length > 255)
throw new ArgumentException("Email is too long");
// 重复的密码验证逻辑
if (string.IsNullOrEmpty(password))
throw new ArgumentException("Password cannot be empty");
if (password.Length < 8)
throw new ArgumentException("Password must be at least 8 characters");
if (!password.Any(char.IsDigit))
throw new ArgumentException("Password must contain at least one digit");
// 创建用户...
}
public void UpdateEmail(int userId, string newEmail)
{
// 重复的邮箱验证逻辑(复制粘贴)
if (string.IsNullOrEmpty(newEmail))
throw new ArgumentException("Email cannot be empty");
if (!newEmail.Contains("@") || !newEmail.Contains("."))
throw new ArgumentException("Invalid email format");
if (newEmail.Length > 255)
throw new ArgumentException("Email is too long");
// 更新邮箱...
}
public void ResetPassword(int userId, string newPassword)
{
// 重复的密码验证逻辑(复制粘贴)
if (string.IsNullOrEmpty(newPassword))
throw new ArgumentException("Password cannot be empty");
if (newPassword.Length < 8)
throw new ArgumentException("Password must be at least 8 characters");
if (!newPassword.Any(char.IsDigit))
throw new ArgumentException("Password must contain at least one digit");
// 重置密码...
}
}
public class UserService
{
private readonly IValidator<string> _emailValidator;
private readonly IValidator<string> _passwordValidator;
public UserService()
{
_emailValidator = new EmailValidator();
_passwordValidator = new PasswordValidator();
}
public void CreateUser(string email, string password)
{
_emailValidator.Validate(email);
_passwordValidator.Validate(password);
// 创建用户...
}
public void UpdateEmail(int userId, string newEmail)
{
_emailValidator.Validate(newEmail);
// 更新邮箱...
}
public void ResetPassword(int userId, string newPassword)
{
_passwordValidator.Validate(newPassword);
// 重置密码...
}
}
// 抽象验证器接口
public interface IValidator<T>
{
void Validate(T value);
}
// 邮箱验证器 - 单一职责,集中管理邮箱验证规则
public class EmailValidator : IValidator<string>
{
public void Validate(string email)
{
if (string.IsNullOrEmpty(email))
throw new ArgumentException("Email cannot be empty");
if (!email.Contains("@") || !email.Contains("."))
throw new ArgumentException("Invalid email format");
if (email.Length > 255)
throw new ArgumentException("Email is too long");
}
}
// 密码验证器 - 单一职责,集中管理密码验证规则
public class PasswordValidator : IValidator<string>
{
private const int MinLength = 8;
public void Validate(string password)
{
if (string.IsNullOrEmpty(password))
throw new ArgumentException("Password cannot be empty");
if (password.Length < MinLength)
throw new ArgumentException($"Password must be at least {MinLength} characters");
if (!password.Any(char.IsDigit))
throw new ArgumentException("Password must contain at least one digit");
}
}
// 违反SoC:一个函数做了太多事情
public void ProcessOrder(Order order)
{
// 验证订单
if (order.Items.Count == 0)
throw new InvalidOperationException("Order has no items");
// 计算总价
decimal total = 0;
foreach (var item in order.Items)
total += item.Price * item.Quantity;
// 应用折扣
if (order.Customer.IsPremium)
total *= 0.9m;
// 处理支付
var paymentResult = ProcessPayment(order.Customer, total);
// 发送邮件
SendEmail(order.Customer.Email, "Order Confirmed", $"Total: {total}");
// 更新库存
foreach (var item in order.Items)
UpdateInventory(item.ProductId, -item.Quantity);
}
// 遵循SoC:每个函数只做一件事
public void ProcessOrder(Order order)
{
ValidateOrder(order);
decimal total = CalculateTotal(order);
total = ApplyDiscount(order.Customer, total);
ProcessPayment(order.Customer, total);
SendOrderConfirmation(order.Customer, total);
UpdateInventory(order.Items);
}
private void ValidateOrder(Order order) { /* ... */ }
private decimal CalculateTotal(Order order) { /* ... */ }
private decimal ApplyDiscount(Customer customer, decimal total) { /* ... */ }
private void SendOrderConfirmation(Customer customer, decimal total) { /* ... */ }
private void UpdateInventory(IEnumerable<OrderItem> items) { /* ... */ }
// 违反SoC:一个类承担多个职责
public class Employee
{
public string Name { get; set; }
public decimal Salary { get; set; }
public decimal CalculateTax() { /* 税务计算 */ }
public void SaveToDatabase() { /* 数据持久化 */ }
public string GenerateReport() { /* 报表生成 */ }
public void SendPayslip() { /* 邮件发送 */ }
}
// 遵循SoC:每个类只有一个职责
public class Employee
{
public string Name { get; set; }
public decimal Salary { get; set; }
}
public class TaxCalculator
{
public decimal CalculateTax(Employee employee) { /* ... */ }
}
public class EmployeeRepository
{
public void Save(Employee employee) { /* ... */ }
}
public class PayslipGenerator
{
public string Generate(Employee employee) { /* ... */ }
}
public class EmailService
{
public void SendPayslip(Employee employee, string payslip) { /* ... */ }
}
// 表示层(Presentation Layer)
public class OrderController : Controller
{
private readonly IOrderService _orderService;
public IActionResult CreateOrder(OrderViewModel model)
{
var dto = MapToDto(model);
_orderService.CreateOrder(dto);
return Ok();
}
}
// 业务逻辑层(Business Logic Layer)
public class OrderService : IOrderService
{
private readonly IOrderRepository _repository;
private readonly IInventoryService _inventoryService;
public void CreateOrder(OrderDto dto)
{
var order = new Order(dto);
_repository.Save(order);
_inventoryService.DeductStock(order.Items);
}
}
// 数据访问层(Data Access Layer)
public class OrderRepository : IOrderRepository
{
private readonly DbContext _context;
public void Save(Order order)
{
_context.Orders.Add(order);
_context.SaveChanges();
}
}
// Model - 数据和业务逻辑
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public decimal GetDiscountedPrice(decimal discountPercent)
{
return Price * (1 - discountPercent / 100);
}
}
// View - 用户界面展示(Razor示例)
// Products/Index.cshtml
// @model IEnumerable<Product>
// @foreach (var product in Model)
// {
// <div>@product.Name - @product.Price</div>
// }
// Controller - 协调Model和View
public class ProductsController : Controller
{
private readonly IProductService _productService;
public IActionResult Index()
{
var products = _productService.GetAllProducts();
return View(products);
}
}
// 使用特性/拦截器分离横切关注点(如日志、缓存、事务)
public class OrderService : IOrderService
{
[Log] // 日志关注点
[Cache(Duration = 300)] // 缓存关注点
[Transaction] // 事务关注点
public Order GetOrder(int id)
{
// 核心业务逻辑,不包含横切关注点的代码
return _repository.GetById(id);
}
}
// 日志切面实现
public class LogAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation($"Executing: {context.ActionDescriptor.DisplayName}");
}
public override void OnActionExecuted(ActionExecutedContext context)
{
_logger.LogInformation($"Executed: {context.ActionDescriptor.DisplayName}");
}
}