AlbertZhao 2021.7.15-

五大设计原则SOLID

主题(Subject):五大设计原则 -> 日期(Date):2021.7.7
> 摘要栏(Cue)
单一职责原则(SRP:Single Responsibility Principle)




里氏替换原则(LSP:Liskov Substitution Principle)



依赖倒置原则(DIP:Dependency Inversion Principle)






接口隔离原则(ISP:Interface Segregation Principle)





迪米特/最少知识原则(LKP:Least Knowledge Principle)

开闭原则(OCP:Open Closed Principle)
> 笔记栏(Notes)
将业务拆分为业务对象(Bo)和业务逻辑(Biz),应该有且仅有一个原因引起类的变化(There should never be more than one reason for a class to change.)在可能的情况下做到一个职责/变化原因来编写一个接口/类,但是职责的定义划分不可度量。对于接口/封装方法,设计的时候要做到单一。类的设计尽量做到只有一个原因引起。

代码任何地方子类可替换父类(子类可以扩展父类的功能,但不能改变父类的功能):1.方法的拓展(增加) 2.方法的覆写(C#中不要进行子类对父类的覆写,需要改变父类的方法,添加virtual,子类为override,违反了开闭原则)

用接口来定义行为。充分使用多态的特性。ICar{void Run();} IDriver{void DriverCar(ICar car) {car.Run();}} JMock工具 依赖的三种方式:构造函数传递、方法注入、接口注入。依赖倒置,将观念从依赖具体类转变为抽象间(抽象类/接口)的依赖。面向接口编程。
1.每个类尽量都有接口或抽象类。(依赖倒置的基本要求)
2.变量的表面类型尽量是接口或者抽象类。
3.尽量不要从具体类(二级以上子类)派生
4.尽量不要覆写基类的方法
5.结合里氏替换原则使用

通过分散定义多个接口,可以预防未来变更的扩展,提高系统的灵活性和可维护性。
1.接口尽量小
2.接口要高内聚(接口中尽量少公布public方法)
3.定制服务接口
4.接口设计要有限度,不能粒度无限小,要考虑实际情况

一个类只和朋友类交流,不与陌生类交流。最好不要一个方法,同时牵扯到两个以上的类。


接口的依赖,而不是具体类的依赖。
1.抽象约束
2.元数据(metadata)控制模块行为—配置文件管理业务的变化。
3.制定项目章程 制定团队定义好的配置文件的种类,自动化脚本生成。
4.封装变化:相同变化->一个接口/抽象类 不同变化->不同
> 总结栏(Summary):拥抱变化,让程序变得更加的Solid(稳定的,稳固的)

1 单例模式

主题(Subject):单例模式 -> 日期(Date):2021.7.8
> 摘要栏(Cue)
单例模式:
为减少内存开销、对资源的多重占用、系统要求有且只有一个对象时使用单例模式。



> 笔记栏(Notes)
定义:一个类只能生成一个对象。

优点:
1.单例模式在内存中只有一个实例,减少了内存开支。特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
2.单例模式可以避免对资源的多重占用。写文件,避免对同一个资源文件同时写操作。
3.单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。

缺点:
1.单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。
2.单例模式对测试是不利的。在并行开发环境中,如果单例模式没有完成,是不能进行测试的,没有接口也不能使用mock的方式虚拟一个对象。

应用场景:
在一个系统中,要求一个类有且仅有一个对象,如果出现多个对象就会出现“不良反应”
1.要求生成唯一序列号的环境;
2.在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
3.创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;
4.需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式)。

拓展:多例模式
在设计时决定在内存中有多少个实例,方便系统进行扩展,修正单例可能存在的性能问题,提供系统的响应速度。例如读取文件,我们可以在系统启动时完成初始化工作,在内存中启动固定数量的reader实例,然后在需要读取文件时就可以快速响应。


> 总结栏(Summary):

代码实例讲解

  1. //单例模式:
  2. public sealed class DeviceDGManager {
  3. /// 仪器管理,单例模式,内存唯一
  4. /// </summary>
  5. private static readonly Lazy<DeviceDGManager> lazy = new Lazy<DeviceDGManager>(() => new DeviceDGManager());
  6. public static DeviceDGManager Instance {
  7. get {
  8. return lazy.Value;
  9. }
  10. }
  11. //Fluke仪器清单列表
  12. public List<DeviceDG> flukeDevices = new List<DeviceDG>();
  13. /// <summary>
  14. /// 根据SN来查询Fluke设备
  15. /// </summary>
  16. /// <param name="SN"></param>
  17. /// <returns></returns>
  18. public DeviceDG GetFlukeDeviceBySN(string SN) {
  19. var temp = flukeDevices.Where(item => item.SN == SN);
  20. if (temp.Count() != 0) {
  21. return temp.FirstOrDefault();
  22. }
  23. return null;
  24. }
  25. }
  26. }
  27. //多例模式:
  28. public class Multiton
  29. {
  30. private static Multiton instance1=null;
  31. private static Multiton instance2=null;
  32. private Multiton()
  33. {
  34. }
  35. public static Multiton getInstance(int whichOne)
  36. {
  37. if(whichOne==1)
  38. {
  39. if(instance1==null)
  40. {
  41. instance1=new Multiton ();
  42. }
  43. return instance1;
  44. }
  45. else
  46. {
  47. if(instance2==null)
  48. {
  49. instance2=new Multiton ();
  50. }
  51. return instance2;
  52. }
  53. }
  54. }

通用代码模板

  1. //单例模式:
  2. public sealed class A {
  3. /// 仪器管理,单例模式,内存唯一
  4. /// </summary>
  5. private static readonly Lazy<A> lazy = new Lazy<A>(() => new A());
  6. public static A Instance {
  7. get {
  8. return lazy.Value;
  9. }
  10. }
  11. //Fluke仪器清单列表
  12. public List<B> listB = new List<B>();
  13. /// <summary>
  14. /// 根据SN来查询Fluke设备
  15. /// </summary>
  16. /// <param name="SN"></param>
  17. /// <returns></returns>
  18. public B GetProductBySN(string SN) {
  19. var temp = listB.Where(item => item.SN == SN);
  20. if (temp.Count() != 0) {
  21. return temp.FirstOrDefault();
  22. }
  23. return null;
  24. }
  25. }
  26. }
  27. //多例模式:
  28. public class Multiton
  29. {
  30. private static Multiton instance1=null;
  31. private static Multiton instance2=null;
  32. private Multiton()
  33. {
  34. }
  35. public static Multiton getInstance(int whichOne)
  36. {
  37. if(whichOne==1)
  38. {
  39. if(instance1==null)
  40. {
  41. instance1=new Multiton ();
  42. }
  43. return instance1;
  44. }
  45. else
  46. {
  47. if(instance2==null)
  48. {
  49. instance2=new Multiton ();
  50. }
  51. return instance2;
  52. }
  53. }
  54. }

2 工厂方法模式

主题(Subject):工厂方法模式 -> 日期(Date):2021.7.8
> 摘要栏(Cue)
工厂方法模式





> 笔记栏(Notes)
定义:Define an interface for creating an object,but let subclasses decide whichclass to instantiate.Factory Method lets a class defer instantiation tosubclasses.(定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。)

优点:
1.使用频率非常高
2.良好的封装性,代码结构清晰。只需要知道产品的类名即可。
3.扩展性非常优秀,如果只需要增加产品类,工厂类无需任何修改即可完成扩展。拥抱变化。
4.屏蔽产品类,调用者只需要关注abstract Product接口即可,无需关心具体的产品。创建产品类延迟到工厂类里面进行创建。
5.高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则,我不需要的就不要去交流;也符合依赖倒置原则,只依赖产品类的抽象;当然也符合里氏替换原则,使用产品子类替换产品父类,没问题!

应用场景:
1.在所有new对象的地方都可以使用,但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码的复杂度。
2.工厂方法模式可以用在异构项目中

拓展:
1.(简单工厂)静态工厂模式:将抽象工厂类换成具体类,把其中的方法变为静态方法,类图简单调用简单。但扩展困难,不符合开闭原则。
2.多工厂,每一个工厂负责一种产品生产。在复杂的应用中一般采用多工厂的方法,然后再增加一个协调类,避免调用者与各个子工厂交流,协调类的作用是封装子工厂类,对高层模块提供统一的访问接口。
3.延迟初始化:延迟加载框架是可以扩展的,例如限制某一个产品类的最大实例化数量,可以通过判断Map中已有的对象数量来实现,这样的处理是非常有意义的,例如JDBC连接数据库,都会要求设置一个MaxConnections最大连接数量,该数量就是内存中最大实例化的数量。通过延迟加载降低对象的产生和销毁带来的复杂性.
> 总结栏(Summary):

代码实例讲解

image.png

  1. using System;
  2. using System.Collections.Generic;
  3. namespace FactoryModern
  4. {
  5. class Program
  6. {
  7. static void Main(string[] args)
  8. {
  9. //声明加人类工厂
  10. AbstractHumanFactory factory = new HumanFactory();
  11. //第一次造白种人
  12. IHuman human = factory.CreateHuman<WhiteHuman>();
  13. human.GetColor();
  14. human.Talk();
  15. //第二次造黑人
  16. human = factory.CreateHuman<BlackHuman>();
  17. human.GetColor();
  18. human.Talk();
  19. }
  20. }
  21. public interface IHuman
  22. {
  23. void GetColor();
  24. void Talk();
  25. }
  26. class BlackHuman : IHuman
  27. {
  28. public void GetColor()
  29. {
  30. Console.WriteLine("My Color is black.");
  31. }
  32. public void Talk()
  33. {
  34. Console.WriteLine("My language is xxxx");
  35. }
  36. }
  37. class WhiteHuman : IHuman
  38. {
  39. public void GetColor()
  40. {
  41. Console.WriteLine("My Color is white.");
  42. }
  43. public void Talk()
  44. {
  45. Console.WriteLine("My language is english");
  46. }
  47. }
  48. class YellowHuman : IHuman
  49. {
  50. public void GetColor()
  51. {
  52. Console.WriteLine("My Color is yellow.");
  53. }
  54. public void Talk()
  55. {
  56. Console.WriteLine("My language is chinese");
  57. }
  58. }
  59. public abstract class AbstractHumanFactory
  60. {
  61. //where约束T为class类型,必须是来自IHuman或者是实现IHuman接口,可创建实例
  62. public abstract T CreateHuman<T>() where T : class,IHuman,new();
  63. }
  64. public class HumanFactory : AbstractHumanFactory
  65. {
  66. public override T CreateHuman<T>()
  67. {
  68. IHuman human = null;
  69. try
  70. {
  71. human = new T();
  72. }
  73. catch
  74. {
  75. Console.WriteLine("人种生成错误");
  76. }
  77. return (T)human;
  78. }
  79. }
  80. }

通用类图及代码模板

企业微信截图_16258309481245.png
抽象产品类Product负责定义产品的共性,实现对事物最抽象的定义;Creator为抽象创建类,也就是抽象工厂,具体如何创建产品类是由具体的实现工厂ConcreteCreator完成的。

//抽象产品类
public abstract class AbsProduct{
    //产品类的公共方法
    public void method1(){
        //业务逻辑处理
    }
    //抽象方法
    public abstract void method2();
}

//具体的产品类可有多个
public class ConcreteProduct1:AbsProduct{
    public override void method2(){
        //业务逻辑处理
    }
}
public class ConcreteProduct2:Product{
    public override void method2(){
        //业务逻辑处理
    }
}

//抽象工厂
public abstract class AbsFactory{
    //返回一个T类型的产品,T限定为Product或派生自它的,限定为class
    public abstract T CreateMethod<T>() where T:class,Product,new();
}

//具体工厂类
public class Factory:AbsFactory{
    public override T CreateMethod<T>(){
        Product product = null;
        try{
            product = new T();
            //或者传参进来 product = (T)Activator.CreateInstance(t.GetType());
        }
        catch(Exception e){
            //异常处理
        }
        return (T)product;
    }
}


//具体工厂类结合依赖注入框架
 public class HumanFactoryDelay : AbstractHumanFactory
    {
    //依赖注入框架Microsoft.Extensions.DependencyInjection
        public static ServiceCollection sc = new ServiceCollection();
        public override T CreateHuman<T>()
        {
            IHuman human = null;
            try
            {
                sc.AddScoped(typeof(IHuman), typeof(T));//将T类型放入到容器中
                var sp = sc.BuildServiceProvider();
                human = sp.GetService<T>();
            }
            catch
            {
                Console.WriteLine("人种生成错误");
            }
            return (T)human;
        }
    }

//场景类Client调用场景
public class Client{
    public static void main(Stirng[] args){
        AbsFactory absFactory = new Factory();
        AbsProduct absProduct = absFactory.CreateMethod<ConcreteProduct1>();
        absProduct.method1();
        absProduct.method2();
    }
}

3 抽象工厂模式

主题(Subject):抽象工厂模式 -> 日期(Date):2021.7.9
抽象工厂模式 > 笔记栏(Notes)
定义:Provide an interface for creating families of related or dependent objectswithout specifying their concrete classes.(为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。)

优点:
1.抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。

缺点:
1.扩展非常困难,严重违反开闭原则


应用场景:
1.一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式。
2.跨操作系统,可以通过抽象工厂模式屏蔽掉操作系统对应用的影响。
> 总结栏(Summary):

工厂方法模式
企业微信截图_16258309481245.png
抽象工厂模式 将产品抽象化,将工厂抽象化
其本质还是一样的,将产品抽象化,再进行产品线的扩充。在抽象工厂中分别暴露三个A B C产品的方法,然后延时到具体工厂中实现。
企业微信截图_16258313661220.png

通用类图及代码模板

image.png

//抽象产品A类
public abstract class AbstractProductA{
    public void ShareMethod(){}
    //每个产品的相同方法不同实现
    public abstract void DoSomething();
}

//A类产品不同型号1
public class ProductA1:AbstractProductA{
    public void DoSomething(){
        //
    }
}

//A类产品不同型号2
public class ProductA2:AbstractProductA{
    public void DoSomething(){
        //
    }
}

//抽象工厂:有几类产品就有几类方法
public abstract class AbstractFactory{
    //创建A类产品
    public abstract AbstractProductA createProductA();
    //创建B类产品
    public abstract AbstractProductB createProductB();
}

//只生产型号1的产品
public class Factory1:AbstractFactory{
    //创建A类产品
    public AbstractProductA createProductA(){
        return new ProductA1;
    }
    //创建B类产品
    public AbstractProductB createProductB(){
        return new ProductB1;
    }
}

//只生产型号2的产品
public class Factory2:AbstractFactory{
    //创建A类产品
    public AbstractProductA createProductA(){
        return new ProductA2;
    }
    //创建B类产品
    public AbstractProductB createProductB(){
        return new ProductB2;
    }
}