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): |
代码实例讲解
//单例模式:
public sealed class DeviceDGManager {
/// 仪器管理,单例模式,内存唯一
/// </summary>
private static readonly Lazy<DeviceDGManager> lazy = new Lazy<DeviceDGManager>(() => new DeviceDGManager());
public static DeviceDGManager Instance {
get {
return lazy.Value;
}
}
//Fluke仪器清单列表
public List<DeviceDG> flukeDevices = new List<DeviceDG>();
/// <summary>
/// 根据SN来查询Fluke设备
/// </summary>
/// <param name="SN"></param>
/// <returns></returns>
public DeviceDG GetFlukeDeviceBySN(string SN) {
var temp = flukeDevices.Where(item => item.SN == SN);
if (temp.Count() != 0) {
return temp.FirstOrDefault();
}
return null;
}
}
}
//多例模式:
public class Multiton
{
private static Multiton instance1=null;
private static Multiton instance2=null;
private Multiton()
{
}
public static Multiton getInstance(int whichOne)
{
if(whichOne==1)
{
if(instance1==null)
{
instance1=new Multiton ();
}
return instance1;
}
else
{
if(instance2==null)
{
instance2=new Multiton ();
}
return instance2;
}
}
}
通用代码模板
//单例模式:
public sealed class A {
/// 仪器管理,单例模式,内存唯一
/// </summary>
private static readonly Lazy<A> lazy = new Lazy<A>(() => new A());
public static A Instance {
get {
return lazy.Value;
}
}
//Fluke仪器清单列表
public List<B> listB = new List<B>();
/// <summary>
/// 根据SN来查询Fluke设备
/// </summary>
/// <param name="SN"></param>
/// <returns></returns>
public B GetProductBySN(string SN) {
var temp = listB.Where(item => item.SN == SN);
if (temp.Count() != 0) {
return temp.FirstOrDefault();
}
return null;
}
}
}
//多例模式:
public class Multiton
{
private static Multiton instance1=null;
private static Multiton instance2=null;
private Multiton()
{
}
public static Multiton getInstance(int whichOne)
{
if(whichOne==1)
{
if(instance1==null)
{
instance1=new Multiton ();
}
return instance1;
}
else
{
if(instance2==null)
{
instance2=new Multiton ();
}
return instance2;
}
}
}
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): |
代码实例讲解
using System;
using System.Collections.Generic;
namespace FactoryModern
{
class Program
{
static void Main(string[] args)
{
//声明加人类工厂
AbstractHumanFactory factory = new HumanFactory();
//第一次造白种人
IHuman human = factory.CreateHuman<WhiteHuman>();
human.GetColor();
human.Talk();
//第二次造黑人
human = factory.CreateHuman<BlackHuman>();
human.GetColor();
human.Talk();
}
}
public interface IHuman
{
void GetColor();
void Talk();
}
class BlackHuman : IHuman
{
public void GetColor()
{
Console.WriteLine("My Color is black.");
}
public void Talk()
{
Console.WriteLine("My language is xxxx");
}
}
class WhiteHuman : IHuman
{
public void GetColor()
{
Console.WriteLine("My Color is white.");
}
public void Talk()
{
Console.WriteLine("My language is english");
}
}
class YellowHuman : IHuman
{
public void GetColor()
{
Console.WriteLine("My Color is yellow.");
}
public void Talk()
{
Console.WriteLine("My language is chinese");
}
}
public abstract class AbstractHumanFactory
{
//where约束T为class类型,必须是来自IHuman或者是实现IHuman接口,可创建实例
public abstract T CreateHuman<T>() where T : class,IHuman,new();
}
public class HumanFactory : AbstractHumanFactory
{
public override T CreateHuman<T>()
{
IHuman human = null;
try
{
human = new T();
}
catch
{
Console.WriteLine("人种生成错误");
}
return (T)human;
}
}
}
通用类图及代码模板
抽象产品类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): |
工厂方法模式
抽象工厂模式 将产品抽象化,将工厂抽象化
其本质还是一样的,将产品抽象化,再进行产品线的扩充。在抽象工厂中分别暴露三个A B C产品的方法,然后延时到具体工厂中实现。
通用类图及代码模板
//抽象产品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;
}
}