我目前正在学习DI和IoC原理。因此,我偶然发现了这样一种情况:我有一个方法,该方法具有无法通过构造函数注入的依赖项。另外,我不能将其作为方法参数传递,因为该实例的创建是有条件的,并且只能使用其自身的参数实例化。这是我的Employee和WorkYear类的超简化版本:
public abstract class Employee
{
private List<WorkYear> _workYears;
// other private fields....
protected Employee(IDependency1 dep, etc...)
{
WorkYears = new List<WorkYear>();
// other components initialization....
}
public IEnumerable<WorkYear> WorkYears
{
get => _workYears.AsReadOnly();
private set => _workYears = value.ToList();
}
public void StartWorking(DateTime joinedCompany)
{
List<PayPeriod> periods = // Calculating periods...
WorkYear year = WorkYears.FirstOrDefault(y => y.CurrentYear == joinedCompany.Year);
if (year == null)
{
// Here is the problem:
year = new WorkYear(joinedCompany.Year, this, periods);
AddYear(year);
}
else
{
// Logic when year not null
}
year.RecalculateAllTime();
}
public void AddYear(WorkYear workYear) => _workYears.Add(workYear);
// More code...
}
public class WorkYear
{
public WorkYear(int currentYear, Employee employee, List<PayPeriod> periods)
{
Employee = employee;
EmployeeId = employee.Id;
CurrentYear = currentYear;
PayPeriods = periods ?? new List<PayPeriod>();
foreach (PayPeriod period in PayPeriods)
{
period.WorkYear = this;
period.WorkYearId = Id;
}
}
// More code...
}
如您所见,如果Employee还没有,我仅需要一个WorkYear的新实例。我发现了一个建议使用简单工厂类来解决类似问题的线程。这样的解决方案可以工作,但是如何处理没有实例化WorkYear的参数?
很高兴看到如何解决此问题的示例。
答案 0 :(得分:0)
我不确定您要做什么,或者为什么`工作年新书需要摘要。您会看到我们无法走得太远。但是,让我们看一下:
我们可以定义一个通用接口:
class Abc(IntEnum):
def __new__(cls, n=100):
value = len(cls.__members__) + n
obj = int.__new__(cls, value)
obj._value_ = value
return obj
A = ()
B = ()
然后描述我们的数据并实施:
public interface IFactory<T, TData>
{
T Create(TData data);
}
最后更新Employee
public class WorkYearData
{
WorkYearData(int currentYear, Employee employee, List<PayPeriod> periods)
{
CurrentYear = currentYear;
Employee = employee;
Periods = periods;
}
public int CurrentYear { get; }
public Employee Employee { get; }
public List<PayPeriod> Periods { get; }
}
public class WorkYearFactory : IFactory<WorkYear, WorkYearData>
{
public WorkYear Create(WorkYearData data)
=> new WorkYear(data.CurrentYear, data.Employee, data.Periods);
}
如您所见,我们确实并没有太多抽象,只是添加了间接。
答案 1 :(得分:0)
这是使用界面隐藏真实对象的另一种方法。
创建一个代表您的工作年份的界面:
.pipe(fs.createWriteStream('lorem_ipsum.wav'));
让您的public interface IWorkYear
{
int CurrentYear { get; }
void RecalculateAllTime();
}
类实现它:
WorkYear
创建一个表示提供者的接口:
public class WorkYear : IWorkYear
{
//Implementation code here
}
让您的public interface IWorkYearProvider
{
IWorkYear CreateNewWorkYear(int year, Employee employee, List<PayPeriod> periods);
}
类使用Employee
接口代替实际的对象:
IWorkYear
我创建了两个测试类来说明:
public abstract class Employee
{
private List<IWorkYear> _workYears;
//Notice the dependency injection here
public Employee(IWorkYearProvider workYearProvider)
{
WorkYearProvider = workYearProvider;
}
//Reference to the dependency
public IWorkYearProvider WorkYearProvider { get; private set; }
public IEnumerable<IWorkYear> WorkYears { get => _workYears.AsReadOnly(); private set => _workYears = value.ToList(); }
public object Id { get; internal set; }
public void StartWorking(DateTime joinedCompany)
{
List<PayPeriod> periods = null; // Calculating periods...
IWorkYear year = WorkYears.FirstOrDefault(y => y.CurrentYear == joinedCompany.Year);
if (year == null)
{
// Use the dependency to create the object
year = WorkYearProvider.CreateNewWorkYear(joinedCompany.Year, this, periods);
_workYears.Add(year);
}
else
{
// Logic when year not null
}
year.RecalculateAllTime();
}
// More code...
}
样品用量:
public class SampleEmployee : Employee
{
public SampleEmployee(IWorkYearProvider provider) : base(provider) { }
}
public class SampleWorkYearProvider : IWorkYearProvider
{
public IWorkYear CreateNewWorkYear(int year, Employee employee, List<PayPeriod> periods)
{
IWorkYear workYear = null;
workYear = new WorkYear(year, employee, periods);
return workYear;
}
}
现在已经抽象出了创作。
我宁愿建议您重新考虑设计。将//Create your provider
IWorkYearProvider provider = new SampleWorkYearProvider();
//Inject it as a dependency
var employee = new SampleEmployee(provider);
//Call the method
employee.StartWorking(DateTime.Today);
中的整个逻辑抽象出来可能更有意义。
答案 2 :(得分:0)
首先,向您的代码注入WorkYear
实例将不会使您的代码独立于WorkYear
,因为Employee
仍然知道该类(如列表List<WorkYear> WorkYears
例如),因此,如果您需要DI,则应使用代表此类的接口(例如IWorkYear
)(此处的列表将是List<IWorkYear> WorkYears
代替)。
现在可以注入和实例化:
设置工厂类,例如:
public static class MyFactory
{
public static object Create(Type classType, object[] data = null)
{
// create the class by reflection
}
}
(要通过反射创建一个类,请检查以下内容:Activator.CreateInstance)
然后更改方法StartWorking
的签名,以便将类型注入方法:
public void StartWorking(Type workYearType, DateTime joinedCompany)
和该行:
year = new WorkYear(joinedCompany.Year, this, periods);
将是:
year = MyFactory.Create(classType, new object[]{ joinedCompany.Year, this, periods});