接口隔离原则:
如果存在具有完全覆盖关系的多个接口(胖瘦接口),会出现这多个接口之间不兼容情况,所以使用接口继承方式解决
设计失误:把太多的功能包含在一个接口里面
● 这就导致实现该接口的类违反了单一职责原则
○ 单一职责原则:一个类只做一件(或一组相关的)事
● 接口隔离原则是从服务调用者的角度来看接口类型,单一职责原则是从服务提供者的角度来看接口类型
● 解决方案就是把胖接口拆成单一的小接口(把本质不同的功能隔离开)
显式实现接口:
显式实现接口时,只有该实例被作为该接口类型进行转换时才能调用该接口的方法
class Demo_Partition3
{
public void test()
{
WarmKiller warmKiller = new WarmKiller();
(warmKiller as IKiller).Kill();
}
}
interface IGentleman
{
void Love();
}
interface IKiller
{
void Kill();
}
class WarmKiller : IGentleman, IKiller
{
public void Love()
{
Console.WriteLine("love");
}
void IKiller.Kill()//显式实现接口
{
throw new NotImplementedException();
}
}
反射
反射:你给我一个对象,我能在不用 new 操作符也不知道该对象的静态类型的情况下,我能给你创建出一个同类型的对象,还能访问该对象的各个成员。
这相当于进一步的解耦,因为有 new 操作符后面总得跟类型,一跟类型就有了紧耦合的依赖。依靠反射创建类型不再需要 new 操作符也无需静态类型,这样使得很多时候耦合可以松到忽略不计。
结合显式调用接口做了一波测试
class Demo_Partition3
{
public void test()
{
WarmKiller warmKiller = new WarmKiller();
(warmKiller as IKiller).Kill();
Type t = warmKiller.GetType();
object o = Activator.CreateInstance(t);
MethodInfo killMethod = t.GetInterface(typeof(IKiller).Name).GetMethod("Kill");
MethodInfo loveMethod = t.GetMethod("Love");
killMethod.Invoke((IKiller)o, null);
loveMethod.Invoke(o, null);
}
}
interface IGentleman
{
void Love();
}
interface IKiller
{
void Kill();
}
class WarmKiller : IGentleman, IKiller
{
public void Love()
{
Console.WriteLine("love");
}
void IKiller.Kill()//显式实现接口
{
Console.WriteLine("kill");
}
}
依赖注入:
个人理解类似于牵线,服务已经为你设定好了需要哪些东西时对应的提供项,缺啥就从里面找,自动为你形成一套创建过程
var sc = new ServiceCollection();
sc.AddScoped(typeof(ITank), typeof(Demo30_HeavyTank));
sc.AddScoped(typeof(IVehecle), typeof(Demo30_MedianTank));
sc.AddScoped<Demo30_Driver>();
var sp = sc.BuildServiceProvider();
Demo30_Driver demo30_Driver1 = sp.GetService<Demo30_Driver>();
demo30_Driver1.Drive();
实操案例:
因为项目采用.net framework架构,如果读取的是.net core的类库会报错(囧)
namespace watch_learn_CSharp
{
class Demo_Reflection_Depencies_Injection
{
public void test()
{
var folder = Path.Combine(Environment.CurrentDirectory, "Animals");
var files = Directory.GetFiles(folder);
var animalTypes = new List<Type>();
//Console.WriteLine(files.Length);
foreach (var item in files)//读文件
{
var assembly = Assembly.LoadFrom(item);//读程序集
var types = assembly.GetTypes();//读程序集中的所有类型
foreach (var type in types)//若有可以发声的类
{
if (type.GetMethod("Voice") != null)
{
animalTypes.Add(type);
}
}
}
while (true)
{
int count = 0;
foreach (var item in animalTypes)
{
Console.WriteLine($"{++count}:{item.Name}");
}
int index = int.Parse(Console.ReadLine());
if (index < count)
{
int times = int.Parse(Console.ReadLine());
var t = animalTypes[index - 1];
var m = t.GetMethod("Voice");
m.Invoke(Activator.CreateInstance(t),new object[] { times});//这里是object数组,里面包含了不定量的实参,估计没有对应的参数列表时会报错
}
else
{
Console.WriteLine("No such an animal.Try again!");
}
}
}
}
}
第一方准备SDK之后,你再在这个基础上建立程序集……
主程序:
class Demo_Reflection_Depencies_Injection
{
public void test()
{
var folder = Path.Combine(Environment.CurrentDirectory, "Animals");
var files = Directory.GetFiles(folder);
var animalTypes = new List<Type>();
//Console.WriteLine(files.Length);
foreach (var item in files)//读文件
{
var assembly = Assembly.LoadFrom(item);//读程序集
var types = assembly.GetTypes();//读程序集中的所有类型
foreach (var type in types)//若有可以发声的类
{
if (type.GetInterfaces().Contains(typeof(IAnimal)) && type.GetInterface(typeof(IAnimal).ToString()) != null)//两种用法都可以,都列出来只是为了验证两者是同一作用
{
Console.WriteLine(type.Name);
if (!type.GetCustomAttributes(false).Any(x => x.GetType() == typeof(UnfinishedAttribute)))
{
animalTypes.Add(type);
}
}
}
}
while (true)
{
int count = 0;
foreach (var item in animalTypes)
{
Console.WriteLine($"{++count}:{item.Name}");
}
Console.WriteLine("Please choose animal");
int index = int.Parse(Console.ReadLine());
if (index <= count)
{
int times = int.Parse(Console.ReadLine());
var t = animalTypes[index - 1];
var m = t.GetMethod("Voice");
IAnimal animal = (IAnimal)Activator.CreateInstance(t);
animal.Voice(times);
}
else
{
Console.WriteLine("No such an animal.Try again!");
}
Console.WriteLine("===================");
}
}
}
Lib内容
因为偷懒,就直接手动添加第一方的 SDK/程序集 了……(也可以模仿上述直接读文件读程序集读类型的步骤……不对!你设计类的时候你不知道这个接口你应该怎么设计??必须手动添加SDK)
以猫为实例:
[Unfinished]//特性
public class Cat:IAnimal
{
public void Voice(int times)
{
for (int i = 0; i < times; i++)
{
Console.WriteLine("miao");
}
}
}
SDK内容:
接口部分:
namespace HelpLib
{
public interface IAnimal
{
void Voice(int times);
}
}
特性定义:
public class UnfinishedAttribute:Attribute
{
}