这是控制反转的一个例子吗?

时间:2009-03-05 16:50:41

标签: c# dependency-injection inversion-of-control

我刚刚完成了James Kovac的article on Inversion of Control and Dependency Injection,然后使用我学到的知识在下面制作了我自己的IoC / DI示例。

我很满意这个例子,因为它:

  • 满足IoC的可测试性 方面,因为它通过传递存储库和MockRepository来实例化Customers
  • 此处授权服务已解除连接,这样您就可以使用不同的规则编写另一个授权服务,然后您可以根据其他条件轻松地将它们交换出来

然而,从这里开始,有些事情似乎很奇怪:

  • 我似乎没有“容器”。在这个意义上,我的Customer类是否“充当容器”?
  • 如果我将此移植到WPF,模块(就Prism而言)适用于此示例(例如,AuthorizationService和Repository是模块吗?)
  • 如果我将此移植到WPF, MVVM适合的位置?通过依赖注入确实拥有MVVM的一部分或者MVVM是完全独立的。

感谢您提供的任何指示。

基于评论的新代码:

using System;
using System.Linq;
using System.Collections.Generic;

namespace TestSimpleDependencyInjection1
{
    class Program
    {
        static void Main(string[] args)
        {
            AuthorizationService authorizationService = new AuthorizationService();

            //real example
            Repository repository = new Repository(authorizationService);
            for (int id = 1; id <= 3; id++)
            {
                Customer customer = repository.GetCustomer(id);
                customer.Display();
            }
            Console.WriteLine();

            //mock test example
            MockRepository mockRepository = new MockRepository(authorizationService);
            Customer mockCustomerAdministrator = repository.GetCustomer(1);
            Customer mockCustomerSalesperson = repository.GetCustomer(2);
            UnitTester.Assert("Administrators have access", mockCustomerAdministrator.GetAuthorizationMessage(), "Access Granted");
            UnitTester.Assert("Salespeople do not have access", mockCustomerAdministrator.GetAuthorizationMessage(), "Access Granted");

            Console.ReadLine();
        }
    }

    public static class UnitTester
    {
        public static void Assert(string title, string value, string expectedResult)
        {
            Console.WriteLine(value == expectedResult ? String.Format("{0}: test succeeded", title) : String.Format("{0}: TEST FAILED!", title));
        }
    }

    public class Customer
    {

        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public AccessGroup AccessGroup { get; set; }
        public AuthorizationService AuthorizationService { get; set; }

        public string GetAuthorizationMessage()
        {
            return this.AuthorizationService.GetAccessMessage(this);
        }

        public Customer()
        {

        }

        public void Display()
        {
            Console.WriteLine("Customer: {1}, {0} ({2}): {3}", this.FirstName, this.LastName, this.AccessGroup, this.GetAuthorizationMessage());
        }
    }

    public class AuthorizationService
    {
        public string GetAccessMessage(Customer customer)
        {
            return customer.AccessGroup == AccessGroup.Administrator ? "Access Granted" : "Access Denied";
        }
    }


    public class Repository : IRepository
    {
        private List<Customer> _customerSet = new List<Customer>();
        private AuthorizationService _authorizationService;

        public Repository(AuthorizationService authorizationService)
        {
            _authorizationService = authorizationService;
            _customerSet.Add(new Customer {AuthorizationService = _authorizationService, ID = 1, FirstName = "Jim", LastName = "Smith", AccessGroup = AccessGroup.Administrator });
            _customerSet.Add(new Customer {AuthorizationService = _authorizationService, ID = 2, FirstName = "John", LastName = "Johnson", AccessGroup = AccessGroup.Administrator });
            _customerSet.Add(new Customer {AuthorizationService = _authorizationService, ID = 3, FirstName = "Hank", LastName = "Rivers", AccessGroup = AccessGroup.Salesperson });
        }

        public Customer GetCustomer(int id)
        {
            return (from c in _customerSet
                    where c.ID == id
                    select c).SingleOrDefault();
        }
    }

    public class MockRepository : IRepository
    {
        private List<Customer> _customerSet = new List<Customer>();
        private AuthorizationService _authorizationService;

        public MockRepository(AuthorizationService authorizationService)
        {
            _authorizationService = authorizationService;
            _customerSet.Add(new Customer { AuthorizationService = _authorizationService, ID = 1, FirstName = "Test1AdministratorFirstName", LastName = "Test1AdministratorLastName", AccessGroup = AccessGroup.Administrator });
            _customerSet.Add(new Customer { AuthorizationService = _authorizationService, ID = 2, FirstName = "Test2SalespersonFirstName", LastName = "Test2SalesPersonLastName", AccessGroup = AccessGroup.Salesperson });
        }

        public Customer GetCustomer(int id)
        {
            return (from c in _customerSet
                            where c.ID == id
                            select c).SingleOrDefault();
        }

    }

    public interface IRepository
    {
        Customer GetCustomer(int id);
    }

    public enum AccessGroup
    {
        Administrator,
        Salesperson
    }
}

AND PER REQUEST,这是原始代码:

using System;
using System.Collections.Generic;

namespace TestSimpleDependencyInjection1
{
    class Program
    {
        static void Main(string[] args)
        {
            AuthorizationService authorizationService = new AuthorizationService();

            //real example
            Repository repository = new Repository();
            for (int id = 1; id <= 3; id++)
            {
                Customer customer = new Customer(id, authorizationService, repository);
                customer.Display();
            }
            Console.WriteLine();

            //mock test example
            MockRepository mockRepository = new MockRepository();
            Customer mockCustomerAdministrator = new Customer(1, authorizationService, mockRepository);
            Customer mockCustomerSalesperson = new Customer(2, authorizationService, mockRepository);
            UnitTester.Assert("Administrators have access", mockCustomerAdministrator.GetAuthorizationMessage(), "Access Granted");
            UnitTester.Assert("Salespeople do not have access", mockCustomerAdministrator.GetAuthorizationMessage(), "Access Granted");

            Console.ReadLine();
        }
    }

    public static class UnitTester
    {
        public static void Assert(string title, string value, string expectedResult)
        {
            Console.WriteLine(value == expectedResult ? String.Format("{0}: test succeeded", title) : String.Format("{0}: TEST FAILED!", title));
        }
    }

    public class Customer
    {
        private AuthorizationService authorizationService;
        private IRepository repository;

        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public AccessGroup AccessGroup { get; set; }

        public string GetAuthorizationMessage()
        {
            return authorizationService.GetAccessMessage(this);
        }

        public Customer(int id, AuthorizationService authorizationService, IRepository repository)
        {
            this.authorizationService = authorizationService;
            this.repository = repository;

            CustomerDB customerDB = repository.GetCustomerDB(id);
            this.ID = customerDB.ID;
            this.FirstName = customerDB.FirstName;
            this.LastName = customerDB.LastName;
            this.AccessGroup = customerDB.AccessGroup;
        }

        public void Display()
        {
            Console.WriteLine("Customer: {1}, {0} ({2}): {3}", this.FirstName, this.LastName, this.AccessGroup, this.GetAuthorizationMessage());
        }
    }

    public class AuthorizationService
    {
        public string GetAccessMessage(Customer customer)
        {
            return customer.AccessGroup == AccessGroup.Administrator ? "Access Granted" : "Access Denied";
        }
    }


    public class Repository : IRepository
    {
        private List<CustomerDB> _customerDBSet = new List<CustomerDB>();

        public Repository()
        {
            _customerDBSet.Add(new CustomerDB { ID = 1, FirstName = "Jim", LastName = "Smith", AccessGroup = AccessGroup.Administrator });
            _customerDBSet.Add(new CustomerDB { ID = 2, FirstName = "John", LastName = "Johnson", AccessGroup = AccessGroup.Administrator });
            _customerDBSet.Add(new CustomerDB { ID = 3, FirstName = "Hank", LastName = "Rivers", AccessGroup = AccessGroup.Salesperson });
        }

        public CustomerDB GetCustomerDB(int id)
        {
            CustomerDB customerDBchosen = null;
            //this should be done with LINQ (couldn't get it CustomerDB to implement IEnumerable correctly)
            foreach (CustomerDB customerDB in _customerDBSet)
            {
                if (customerDB.ID == id)
                {
                    customerDBchosen = customerDB;
                    break;
                }
            }
            return customerDBchosen;
        }
    }

    public class MockRepository : IRepository
    {
        public CustomerDB GetCustomerDB(int id)
        {
            switch (id)
            {
                case 1:
                    return new CustomerDB { ID = 1, FirstName = "Test1AdministratorFirstName", LastName = "Test1AdministratorLastName", AccessGroup = AccessGroup.Administrator };
                case 2:
                    return new CustomerDB { ID = 2, FirstName = "Test2SalespersonFirstName", LastName = "Test2SalesPersonLastName", AccessGroup = AccessGroup.Salesperson };
                default:
                    return null;
            }
        }
    }

    public interface IRepository
    {
        CustomerDB GetCustomerDB(int id);
    }

    public class CustomerDB
    {
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public AccessGroup AccessGroup { get; set; }
    }

    public enum AccessGroup
    {
        Administrator,
        Salesperson
    }
}

2 个答案:

答案 0 :(得分:5)

您的代码以非常严肃的方式违反了单一责任主体。

http://en.wikipedia.org/wiki/Single_responsibility_principle

您的Customer对象不应从存储库加载自身,存储库应该加载Customer对象并将其交还给调用者。

我希望更像是:

Customer customer = repository.GetCustomer(3);

答案 1 :(得分:1)

在大多数情况下,使用Switch语句会违反SRP。请check this out了解如何消除代码中的switch语句。挑战与挑战编写松散耦合代码的美妙之处在于消除if,if else&amp;转换声明。