Dependency Injection, Service Locator, Inversion of Control, Dependency Inversion Principle, … Viele Begriffe die irgendwie das Gleiche zu sagen scheinen und sich dann doch wieder unterscheiden. Sicher ist nur, dass es sich um lose Kopplung handelt. Dass wir dank dieser ominösen Begriffe wartbare Software erstellen können, die leichter zu erweitern ist und sich darüber hinaus auch noch gut testen lässt.
Der Vortrag griff die zuvor genannten Begriffe auf und erläuterte ihre Zusammenhänge. Dabei war das Ziel mit altbekannten Vorurteilen aufzuräumen und bei der Entscheidung zu helfen wo Softwarebestandteile wirklich entkoppelt werden sollten und welche Antipatterns sich beim Praxiseinsatz ergeben können. Dabei sahen wir diverse Beispiele des Einsatzes der SOLID Prinzipien und warum Dependency Injection allein eben nicht zu besserer Software führt.
DevDay 2016: Hendrik Lösch - Lose gekoppelt wie nie: DI vs. IoC
1.
2.
3. 1. It is hard to change because every change affects too many other parts
of the system. (Rigidity - Starr)
2. When you make a change, unexpected parts of the system break.
(Fragility - Zerbrechlich)
3. It is hard to reuse in another application because it cannot be
disentangled from the current application. (Immobility - Unbeweglich)
Quelle: http://www.objectmentor.com/resources/articles/dip.pdf
11. Robert C. Martin
(Uncle Bob)
The SOLID principles are not rules. They are not laws.
They are not perfect truths. They are statements on
the order of “An apple a day keeps the doctor away.”
This is a good principle, it is good advice, but it’s not a
pure truth, nor is it a rule.
“
”
Quelle: https://sites.google.com/site/unclebobconsultingllc/getting-a-solid-start
12. ingle Responsibility Principle
pen Closed Principle
iskov Substitution Principle
nterface Segregation Principle
ependency Inversion Principle
S
O
L
I
D
13. ingle Responsibility Principle
pen Closed Principle
iskov Substitution Principle
nterface Segregation Principle
ependency Inversion Principle
S
O
L
I
D
Eine Klasse sollte nur eine Verantwortlichkeit
haben.
Quelle: http://www.clean-code-developer.de/
14. ingle Responsibility Principle
pen Closed Principle
iskov Substitution Principle
nterface Segregation Principle
ependency Inversion Principle
S
O
L
I
D
Eine Klasse sollte offen für Erweiterungen, jedoch
geschlossen für Modifikationen sein.
Quelle: http://www.clean-code-developer.de/
15. ingle Responsibility Principle
pen Closed Principle
iskov Substitution Principle
nterface Segregation Principle
ependency Inversion Principle
S
O
L
I
D
Abgeleitete Klassen sollten sich so verhalten wie es
von ihren Basistypen erwartet wird.
Quelle: http://www.clean-code-developer.de/
16. ingle Responsibility Principle
pen Closed Principle
iskov Substitution Principle
nterface Segregation Principle
ependency Inversion Principle
S
O
L
I
D
Interfaces sollten nur die Funktionalität
wiederspiegeln die ihre Klienten erwarten.
Quelle: http://www.clean-code-developer.de/
17. ingle Responsibility Principle
pen Closed Principle
iskov Substitution Principle
nterface Segregation Principle
ependency Inversion Principle
S
O
L
I
D
High-Level Klassen sollen nicht von Low-Level Klassen abhängig
sein, sondern beide von Abstraktionen.
Abstraktionen sollen nicht von Details abhängig sein, sondern
Details von Abstraktionen.
Quelle: Wikipedia.org
18. High-Level Klassen sollen nicht von Low-Level
Klassen abhängig sein, sondern beide von
Abstraktionen.
Abstraktionen sollen nicht von Details abhängig sein,
sondern Details von Interfaces.
19. High-Level Klassen sollen nicht von Low-Level Klassen abhängig sein…
Klient
Leistungs-
träger
High-Level Low-Level
20. High-Level Klassen sollen nicht von Low-Level Klassen abhängig sein…
Klient
Leistungs-
träger
High-Level Low-Level
…
…
…
21. High-Level Klassen sollen nicht von Low-Level Klassen abhängig sein…
Person Bauer
High-Level Low-Level
Süßer
Apfel
23. High-Level Klassen sollen nicht von Low-Level
Klassen abhängig sein, sondern beide von
Abstraktionen.
Abstraktionen sollen nicht von Details abhängig sein,
sondern Details von Interfaces.
24. High-Level Klassen sollen nicht von Low-Level
Klassen abhängig sein, sondern beide von
Abstraktionen.
Abstraktionen sollen nicht von Details abhängig sein,
sondern Details von Interfaces.
27. High-Level Klassen sollen nicht von Low-Level
Klassen abhängig sein, sondern beide von
Abstraktionen.
Abstraktionen sollen nicht von Details abhängig sein,
sondern Details von Abstraktionen.
28. High-Level Klassen sollen nicht von Low-Level
Klassen abhängig sein, sondern beide von
Abstraktionen.
Abstraktionen sollen nicht von Details abhängig sein,
sondern Details von Abstraktionen.
42. public class StudentContext : DbContext
{
public StudentContext() : base()
{}
public DbSet<StudentEntity> Students { get; set; }
}
Creation
Inversion
43. public class StudentContext : DbContext, IStudentContext
{
public StudentContext() : base()
{}
public DbSet<StudentEntity> Students { get; set; }
}
public class IStudentContext
{
DbSet<StudentEntity> Students { get; set; }
}
Creation
Inversion
44. Creation
Inversion
public class StudentManagementViewModel
{
StudentContext context;
public StudentEntity Student { get; set; }
public StudentManagementViewModel()
{
this.context = new StudentContext();
}
public void ShowStudent(string name)
{
this.Student =
this.context.Students.FirstOrDefault<StudentEntity>
(s => s.StudentName == name);
}
}
45. Creation
Inversion
public class StudentManagementViewModel
{
IStudentContext context;
public StudentEntity Student { get; set; }
public StudentManagementViewModel()
{
this.context = ServiceLocator.Create<IStudentContext>();
}
public void ShowStudent(string name)
{
this.Student =
this.context.Students.FirstOrDefault<StudentEntity>
(s => s.StudentName == name);
}
}
46. Creation
Inversion
public class StudentManagementViewModel
{
IStudentContext context;
public StudentEntity Student { get; set; }
public StudentManagementViewModel(IStudentContext context)
{
this.context = context;
}
public void ShowStudent(string name)
{
this.Student =
this.context.Students.FirstOrDefault<StudentEntity>
(s => s.StudentName == name);
}
}
48. public class StudentContext : DbContext, IStudentContext
{
public StudentContext() : base()
{}
public DbSet<StudentEntity> Students { get; set; }
}
public class IStudentContext
{
DbSet<StudentEntity> Students { get; set; }
}
Interface
Inversion
49. public class IStudentRepository
{
IQueryable<StudentEntity> Students { get; set; }
}
Interface
Inversion
public class StudentContext : DbContext, IStudentRepository
{
public StudentContext() : base()
{
// ...
}
private DbSet<StudentEntity> students;
public IQueryable<StudentEntity> Students { get{ return this.students} }
}
50. [Table("StudentInfo")]
public class StudentEntity
{
public StudentEntity() { }
[Key]
public int SID { get; set; }
[Column("Name", TypeName = "ntext")]
[MaxLength(20)]
public string StudentName { get; set; }
[Column("BDate", TypeName = "datetime")]
public DateTime BirthDate { get; set; }
[NotMapped]
public int? Age { get;}
}
Interface
Inversion
51. public class Student
{
public int SID { get; set; }
public string Name { get; set; }
public DateTime BirthDate { get; set; }
public int? Age { get; }
}
Interface
Inversion
public class IStudentRepository
{
IQueryable<Student> Students { get; set; }
}
[Table("StudentInfo")]
public class StudentEntity
{
[Key]
public int SID { get; set; }
[Column("Name", TypeName = "ntext")]
[MaxLength(20)]
public string StudentName { get; set; }
[Column("BDate", TypeName = "datetime")]
public DateTime BirthDate { get; set; }
}
52. Interface
Inversion
public class StudentManagementViewModel
{
IStudentContext context;
public StudentEntity Student { get; set; }
public StudentManagementViewModel(IStudentContext context)
{
this.context = context;
}
public void ShowStudent(string name)
{
this.Student =
this.context.Students.FirstOrDefault<StudentEntity>
(s => s.StudentName == name);
}
}
53. Interface
Inversion
public class StudentManagementViewModel
{
IStudentRepository repository;
public Student Student { get; set; }
public StudentManagementViewModel(IStudentRepository repository)
{
this.repository = repository;
}
public void ShowStudent(string name)
{
this.Student =
this.repository.Students.FirstOrDefault<Student>
(s => s.StudentName == name);
}
}
61. „The real problem is that programmers have spent far too
much time worrying about efficiency in the wrong places and
at the wrong times; premature optimization is the root of all
evil (or at least most of it) in programming.“
Quelle: https://en.wikiquote.org/wiki/Donald_Knuth
Donald Knuth