Is this a proper implementation of n-layer architecture?

前端 未结 4 2002
一生所求
一生所求 2021-02-06 17:52

I have been learning C# for the last year or so and trying to incorporate best practices along the way. Between StackOverflow and other web resources, I thought I was on the ri

4条回答
  •  爱一瞬间的悲伤
    2021-02-06 18:04

    Things you want to consider adding: validation, property change notification, data binding, etc... One common issue when separating each class in multiple classes (DAL, BLL, etc...) is often you end up with a lot of code you need to duplicate. Another problem is if you need some intimacy between those classes, you'll have to create internal members (interfaces, fields, etc.)

    This is what I would do, build a unique consistent Domain Model, something like this:

    public class Product: IRecord, IDataErrorInfo, INotifyPropertyChanged
    {
        // events
        public event PropertyChangedEventHandler PropertyChanged;
    
        // properties
        private int _id;
        public virtual int Id
        {
            get
            {
                return _id;
            }
            set
            {
                if (value != _id)
                {
                    _id = value;
                    OnPropertyChanged("Id");
                }
            }
        }
    
        private string _name;
        public virtual string Name
        {
            get
            {
                return _name;
            }
            set
            {
                if (value != _name)
                {
                    _name = value;
                    OnPropertyChanged("Name");
                }
            }
        }
    
        // parameterless constructor (always useful for serialization, winforms databinding, etc.)
        public Product()
        {
            ProductId = 0;
            Name = String.Empty;
        }
    
        // update methods
        public virtual void Save()
        {
           ValidateThrow();
           ... do save (insert or update) ...
        }
    
        public virtual void Delete()
        {
           ... do delete ...
        }    
    
        // validation methods
        public string Validate()
        {
           return Validate(null);
        }
    
        private void ValidateThrow()
        {
          List exceptions = new List();
          SummaryValidate(exceptions,memberName);
          if (exceptions.Count != 0)
             throw new CompositeException(exceptions);
        }
    
        public string Validate(string memberName)
        {
          List exceptions = new List();
          SummaryValidate(exceptions,memberName);
          if (exceptions.Count == 0)
            return null;
    
          return ConcatenateAsString...(exceptions);
        }
    
        string IDataErrorInfo.Error
        {
          get
          {
             return Validate();
          }
        }
    
        string IDataErrorInfo.this[string columnName]
        {
          get
          {
            return validate(columnName);
          }
        }
    
        public virtual void SummaryValidate(IList exceptions, string memberName)
        {
           if ((memberName == null) || (memberName == "Name"))
           {
             if (!... validate name ...)
                exceptions.Add(new ValidationException("Name is invalid");
           }
        }
    
        protected void OnPropertyChanged(string name)
        {
           OnPropertyChanged(new PropertyChangedEventArgs(name));
        }
    
        // property change notification
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if ((PropertyChanged != null)
                PropertyChanged(this, e);
        }
    
        // read from database methods
        protected virtual Read(IDataReader reader)
        {
          Id = reader.GetInt32(reader.GetOrdinal("Id"));
          Name = = reader.GetString(reader.GetOrdinal("Id"));
          ...
        }
    
        void IRecord.Read(IDataReader reader)
        {
          Read(reader);
        }
    
        // instance creation methods
        public static Product GetById(int id)
        {
            // possibly use some cache (optional)
            Product product = new Product();
            using (IDataReader reader = GetSomeReaderForGetById...(id))
            {
                if (!reader.Read())
                  return null;
    
                ((IRecord)product).Read(reader);
                return product;
            }
        }
    
        public static List GetAll()
        {
            // possibly use some cache (optional)
            List products = new List(); // if you use WPF, an ObservableCollection would be more appropriate?
            using (IDataReader reader = GetSomeReaderForGetAll...(id))
            {
                while (reader.Read())
                {
                  Product product = new Product();
                  ((IRecord)product).Read(reader);
                  products.Add(product);
                }
            }
            return products;
        }
    }
    
    // an interface to read from a data record (possibly platform independent)
    public interface IRecord
    {
      void Read(IDataReader reader);
    }
    

提交回复
热议问题