依赖倒置原则

依赖倒置原则:上层模块不应该依赖于低层模块,二者应该通过抽象依赖,就是说应该依赖于抽象,而不是依赖于细节,面向抽象编程。

看下面的代码:

学生类:



public class Student
{

public int Id { get; set; }
public string Name { get; set; }

public void PlayiPhone(iPhone phone)
{
Console.WriteLine("这里是{0}", this.Name);
phone.Call();
phone.Text();
}

public void PlayLumia(Lumia phone)
{
Console.WriteLine("这里是{0}", this.Name);
phone.Call();
phone.Text();
}
}


 

手机抽象类:



public abstract class AbstractPhone
{
public int Id { get; set; }
public string Branch { get; set; }
public abstract void Call();
public abstract void Text();
}


 

各种手机类:



/// <summary>
/// iPhone
/// </summary>
public class iPhone : AbstractPhone
{
public override void Call()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}
public override void Text()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}
}

public class Lumia : AbstractPhone
{
public override void Call()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}
public override void Text()
{
Console.WriteLine("User {0} Text", this.GetType().Name);
}

public void New()
{ }
}


 

调用:



public class DIPShow
{
public static void Show()
{
Console.WriteLine("**************DIPShow***************");
//Student 为上层 手机为低层 因为学生要用手机,所以学生是处于高层的
Student student = new Student()
{
Id = 191,
Name = "候鸟班长"
};

{
iPhone phone = new iPhone();
student.PlayiPhone(phone);
}
{
Lumia phone = new Lumia();
student.PlayLumia(phone);
}
}
}


 

 从上面的代码逻辑中我们可以得知,Student 为上层,手机为低层  因为学生要用手机,所以学生是处于高层的。依赖倒置原则又要求我们说高层不能直接依赖于底层,二者要通过抽象进行依赖,现在的代码也能实现功能,但是后期如果说要增加不同的手机类别的话,在学生类中,就要不断改动学生类,增加学生类中使用手机的方法,此时手机和学生是依赖于细节的,所以我们需要将二者依赖于抽象,这样的话后期不管增加多少中手机品类都不用更改学生类,因为手机的变化本来就不应该和学生有联系,现在的耦合很严重,改动如下:

学生类:



public class Student
{
private AbstractPhone phone = null;
public Student(AbstractPhone phone)
{
this.phone = phone;
}
public int Id { get; set; }
public string Name { get; set; }
public void Play()
{
Console.WriteLine("这里是{0}", this.Name);
this.phone.Call();
this.phone.Text();
}

}


 

调用:



public class DIPShow
{
public static void Show()
{
Console.WriteLine("**************DIPShow***************");
//Student 为上层 手机为低层 因为学生要用手机,所以学生是处于高层的
Student student = new Student(new iPhone())
{
Id = 191,
Name = "候鸟班长"
};
student.Play();
}
}


 

这样就实现依赖于抽象,耦合降低了。

 如果你的东西根本不会变化了,那就不需要考虑依赖倒置原则。

好处:扩展性更高了,

 

接口隔离原则

接口隔离原则:客户端不应该依赖它不需要的接口; 一个类对另一个类的依赖应该建立在最小的接口上;或者说实现一个接口的时候,只需要自己必须的功能。

接口就是作为一个约束,必须实现全部的接口。

看下面的方法,手机继承了一个基类,这个基类是作为手机存在必须要实现存在的功能,是作为这个物品本质上存在的属性和行为,但是手机也有不同的,也存在不同的功能,所以我们可以通过接口来定义并实现它们:



public abstract class AbstractPhone
{
public int Id { get; set; }
public string Branch { get; set; }
public abstract void Call();
public abstract void Text();
}

/// <summary>
/// 一个大而全的接口
/// </summary>
public interface IExtend
{
void Photo();
void Online();
void Game();
void Record();
void Movie();
void Map();
void Pay();
}


 

华为手机:



public class Honor : AbstractPhone, IExtend
{
public override void Call()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}

public override void Text()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}

public void Photo()
{
Console.WriteLine("User {0} Photo", this.GetType().Name);
}

public void Online()
{
Console.WriteLine("User {0} Online", this.GetType().Name);
}

public void Game()
{
Console.WriteLine("User {0} Game", this.GetType().Name);
}

public void Map()
{
Console.WriteLine("User {0} Map", this.GetType().Name);
}

public void Pay()
{
Console.WriteLine("User {0} Pay", this.GetType().Name);
}

public void Record()
{
Console.WriteLine("User {0} Record", this.GetType().Name);
}

public void Movie()
{
Console.WriteLine("User {0} Movie", this.GetType().Name);
}
}


 

IPhone:



/// <summary>
/// OldMan 老人机
/// </summary>
public class OldMan : AbstractPhone, IExtend
{
public override void Call()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}
public override void Text()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}

public void Photo()
{
Console.WriteLine("User {0} Photo", this.GetType().Name);
}

public void Online()
{
Console.WriteLine("User {0} Online", this.GetType().Name);
}

public void Game()
{
Console.WriteLine("User {0} Game", this.GetType().Name);
}

public void Map()
{
Console.WriteLine("User {0} Map", this.GetType().Name);
}

public void Pay()
{
Console.WriteLine("User {0} Pay", this.GetType().Name);
}

public void Record()
{
Console.WriteLine("User {0} Record", this.GetType().Name);
}

public void Movie()
{
Console.WriteLine("User {0} Movie", this.GetType().Name);
}
}


 

 

但是现在有一个问题,接口作为一个约束,必须要实现它的所有方法,但是老人机没办法全部实现的,因为老人机没有导航功能,也没有支付功能等,IExtend接口功能太全了,所以我们应该拆分一下,保证它的灵活性。接口是能够多实现的,但是继承只能单继承。



/// <summary>
///
/// </summary>
public interface IExtend
{
void Photo();
void Online();
void Game();

}

public interface IExtendAdvanced
{
void Record();
void Movie();
void Map();
void Pay();
}


 

手机类:



/// <summary>
/// iPhone
/// </summary>
public class iPhone : AbstractPhone, IExtend, IExtendAdvanced
{
public override void Call()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}
public override void Text()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}

public void Photo()
{
Console.WriteLine("User {0} Photo", this.GetType().Name);
}

public void Online()
{
Console.WriteLine("User {0} Online", this.GetType().Name);
}

public void Game()
{
Console.WriteLine("User {0} Game", this.GetType().Name);
}

public void Map()
{
Console.WriteLine("User {0} Map", this.GetType().Name);
}

public void Pay()
{
Console.WriteLine("User {0} Pay", this.GetType().Name);
}

public void Record()
{
Console.WriteLine("User {0} Record", this.GetType().Name);
}

public void Movie()
{
Console.WriteLine("User {0} Movie", this.GetType().Name);
}
}

/// <summary>
/// OldMan 老人机
/// </summary>
public class OldMan : AbstractPhone, IExtend
{
public override void Call()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}
public override void Text()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}

public void Photo()
{
Console.WriteLine("User {0} Photo", this.GetType().Name);
}

public void Online()
{
Console.WriteLine("User {0} Online", this.GetType().Name);
}

public void Game()
{
Console.WriteLine("User {0} Game", this.GetType().Name);
}
}


 

比如说,我又新加了一个相机,相机默认只能拍照和上网,我再次进行接口的拆分:



/// <summary>
///
/// </summary>
public interface IExtend
{
void Game();
}

public interface IExtendAdvanced
{
void Record();
void Movie();
void Map();
void Pay();
}
/// <summary>
/// 拆分出来的 相机所具有的方法 IExtend接口方法又少了
/// </summary>
public interface IExtendPhontography
{
void Photo();
void Online();
}


 

 手机相机类:



/// <summary>
/// iPhone
/// </summary>
public class iPhone : AbstractPhone, IExtend, IExtendAdvanced, IExtendPhontography
{
public override void Call()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}
public override void Text()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}

public void Photo()
{
Console.WriteLine("User {0} Photo", this.GetType().Name);
}

public void Online()
{
Console.WriteLine("User {0} Online", this.GetType().Name);
}

public void Game()
{
Console.WriteLine("User {0} Game", this.GetType().Name);
}

public void Map()
{
Console.WriteLine("User {0} Map", this.GetType().Name);
}

public void Pay()
{
Console.WriteLine("User {0} Pay", this.GetType().Name);
}

public void Record()
{
Console.WriteLine("User {0} Record", this.GetType().Name);
}

public void Movie()
{
Console.WriteLine("User {0} Movie", this.GetType().Name);
}
}

/// <summary>
/// OldMan 老人机
/// </summary>
public class OldMan : AbstractPhone, IExtend
{
public override void Call()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}
public override void Text()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}

public void Photo()
{
Console.WriteLine("User {0} Photo", this.GetType().Name);
}

public void Online()
{
Console.WriteLine("User {0} Online", this.GetType().Name);
}

public void Game()
{
Console.WriteLine("User {0} Game", this.GetType().Name);
}
}
/// <summary>
///相机 假设相机只能拍照和上网
/// </summary>
public class Camera : IExtendPhontography
{
/// <summary>
/// 拍照
/// </summary>
public void Photo()
{
Console.WriteLine("User {0} Photo", this.GetType().Name);
}
/// <summary>
/// 录音
/// </summary>
public void Online()
{
Console.WriteLine("User {0} Online", this.GetType().Name);
}

}


 

 为什么分要对接口进行拆分呢?比如说新进相机之后,我不再拆分IExtend接口,我新建一个接口IExtendPhontographyTest,IExtend接口不动:



/// <summary>
///
/// </summary>
public interface IExtend
{
void Game();
void Photo();
void Online();
}

public interface IExtendAdvanced
{
void Record();
void Movie();
void Map();
void Pay();
}
/// <summary>
/// 拆分出来的 相机所具有的方法 IExtend接口方法又少了
/// </summary>
public interface IExtendPhontographyTest
{
void Photo();
void Online();
}


 

实现类:



/// <summary>
///相机 假设相机只能拍照和上网
/// </summary>
public class Camera : IExtendPhontographyTest
{
/// <summary>
/// 拍照
/// </summary>
public void Photo()
{
Console.WriteLine("User {0} Photo", this.GetType().Name);
}
/// <summary>
/// 录音
/// </summary>
public void Online()
{
Console.WriteLine("User {0} Online", this.GetType().Name);
}

}


 

这样功能上是没问题的,但是这样的话就少了复用性,但是如果使用拆分接口的形式的话,就能够实现复用性:



public class ISPShow
{
public static void Show()
{
IExtendPhontography phontography = new iPhone();
IExtendPhontography camara = new Camera();
Photography(camara);
Photography(phontography);
}

/// <summary>
/// 只要是实现了这个接口IExtendPhontography的类都可以调用这个方法
/// </summary>
/// <param name="extend"></param>
public static void Photography(IExtendPhontography extend)
{
extend.Photo();
extend.Online();
}

}


 

IPhone和camera类都实现了IExtendPhontography类,所以也都能调用这个方法,但是如果只是另外新建了一个类的话,这个方法就只能相机类能用了。 

 

所以说,接口隔离原则希望我们能够尽量将接口拆分一下,保证它的灵活性,只依赖于自己本身需要的接口,也是依赖倒置的延续,复用性更强,都是为了未来更好 的扩展开放, c#中很多封装的类都是这种形式,实现多接口比如List,Dictionary。

最后,为什么我们要拆分接口呢?因为不能让类型实现自己没有的功能,也能让方法具备复用性。

究竟如何设计呢?

1 接口不能太大,否则会实现不需要的功能

2 接口尽量的小,但是一致的功能应该在一起,也不能过度设计。

3 接口合并:如果一个业务包含多个步骤,我们不能把步骤都暴露,而是提供一个入口即可。比如手机定位,定位肯定要有很多步骤,不能都开放出来,只留出一个定位的接口就行。

开闭原则

开闭原则:对扩展开发,对修改关闭。如果有功能扩展变化的需求,希望是增加而不是修改 ,尽量不影响之前的功能

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

IExtendPhontographyTest