将业务层类更改为松散耦合

时间:2018-06-13 08:07:01

标签: c#

我正在处理以下代码。我正在处理数据访问adon.net图层。我的业务层类名为UserBAL,我遇到了问题。问题是我在UserBAL的构造函数中创建了dal和dbmanager的实例。如何将此更改为UserBAL的松散耦合?希望你明白我的意思。

public interface IEntity
{
    int Id { get; set; }
    int DoSomething(string one, int two);
}

public class User : IEntity
{
    public int Id { get; set; }
    public int DoSomething(string one, int two)
    {
        throw new NotImplementedException();
    }

    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
}

public class UserBal //busines logic
{
    private readonly IRepositoryDal<User> _userRepositoryDal;

    public UserBal()
    {
        _userRepositoryDal  = new UserRepositoryDal(new DbManager("sqlserver?"));
    }

    public IEnumerable<User> SearchByName(string name)
    {
        return _userRepositoryDal.SearchByName(name);
    }
}

interface IRepositoryDal<T> where T : IEntity
{
    IEnumerable<T> SearchByName(string username);
    T SearchById(string id);
    void Update(T entity);
    void Remove(T entity);
    void Add(T entity);
}

public class UserRepositoryDal: IRepositoryDal<User>
{
    private readonly IDbManager _dbManager;

    public UserRepositoryDal(IDbManager dbManager)
    {
        //read from either singleton or configuration file !!
        _dbManager = dbManager;
    }
    public IEnumerable<User> SearchByName(string username)
    {                                  
            var parameters = new List<IDbDataParameter>
            {
                _dbManager.CreateParameter("@FirstName", 50, username, DbType.String),
            };

        var userDataTable = _dbManager.GetDataTable("storedpr2",
            CommandType.StoredProcedure, parameters.ToArray());

        foreach (DataRow dr in userDataTable.Rows)
        {
            var user = new User
            {
                Id = int.Parse(dr["Id"].ToString()),
                Firstname = dr["Firstname"].ToString(),
                Lastname = dr["LastName"].ToString(),
                Email = dr["Email"].ToString()
            };

            yield return user;
        }

    }
    public User SearchById(string id)
    {
        var parameters = new List<IDbDataParameter>
        {
            _dbManager.CreateParameter("@Id", 50, id, DbType.Int32),
        };

        var userDataTable = _dbManager.GetDataTable("storedpr2",
            CommandType.StoredProcedure, parameters.ToArray());

        return new User
        {
            Id = int.Parse(userDataTable.Rows[0]["Id"].ToString()),
            Firstname = userDataTable.Rows[0]["Firstname"].ToString(),
            Lastname = userDataTable.Rows[0]["LastName"].ToString(),
            Email = userDataTable.Rows[0]["Email"].ToString()
        };
    }

    public void Update(User entity)
    {
        throw new System.NotImplementedException();
    }

    public void Remove(User entity)
    {
        throw new System.NotImplementedException();
    }

    public void Add(User entity)
    {
        throw new System.NotImplementedException();
    }
}

public partial class FrmLogin : Form
{
    private readonly UserBal _userBal;

    public FrmLogin()
    {
        InitializeComponent();
         _userBal = new UserBal();
    }
}

2 个答案:

答案 0 :(得分:0)

您应该使用dependency injection,并且对于所需的依赖项,您可以使用构造函数注入,例如:

public class UserBal
{
    private readonly IRepositoryDal<User> _userRepositoryDal;

    public UserBal(IRepositoryDal<User> userRepositoryDal)
    {
        _userRepositoryDal = userRepositoryDal 
          ?? throw new ArgumentNullException(nameof(userRepositoryDal));
    }

    ...
}

答案 1 :(得分:0)

依赖注入是最佳选择。以下是您情况的简化示例。

鉴于你的课程可能是这样的:

public interface IEntity { }
public interface IRepositoryDal<T> where T : IEntity { }
public interface IDbManager { }

public class User : IEntity { }

public class UserBal //busines logic
{
    [Injectivity.Attributes.Inject]
    private IRepositoryDal<User> _userRepositoryDal;
}

public class UserRepositoryDal: IRepositoryDal<User>
{
    [Injectivity.Attributes.Inject]
    private IDbManager _dbManager;
}

public class DbManager : IDbManager
{
    [Injectivity.Attributes.Construct()]
    public DbManager([Injectivity.Attributes.Key("dbKey", typeof(string))] string x)
    {
        Console.WriteLine($"DbManager created with parameter \"{x}\"");
    }
}

...然后这段代码:

var context = Injectivity.Context.CreateRoot();

context.SetConfig<string>("dbKey", "sqlserver?");
context.SetFactory<IDbManager, DbManager>();
context.SetFactory<IRepositoryDal<User>, UserRepositoryDal>();
context.SetFactory<UserBal, UserBal>();

var user = context.Resolve<UserBal>();

...将产生此输出:

DbManager created with parameter "sqlserver?"

现在,我使用了多年前写过的DI容器。它非常灵活。

因此,对context.Resolve<UserBal>();的调用会在看到需要注入的内容的链条上运行,以创建所有对象的所有实例。最终,UserBal的创建需要创建DbManager,因此需要输出。

您通常不会明确注册每个工厂。通常,您会将属性放在要注册的所有类上,然后使用context.Register(Assembly.LoadFrom("My.DLL"));或创建XML配置文件并调用context.LoadConfig(XDocument.Load("config.xml"));

你甚至可以这样做:

context.SetDecorator<IRepositoryDal<User>, UserRepositoryDalDecorator>();

这将导致对context.Resolve<IRepositoryDal<User>>()[Inject]属性的所有调用自动将真实实例包装在此装饰器中。非常适合拦截方法调用以进行调试。