通过反射,破坏单例设计模式
internal class Program{static void Main(string[] args){//懒汉式//for (int i = 0; i < 10; i++)//{// Thread th = new Thread(() => {// LazyManClass lazyManClass = LazyManClass.GetLazyMan();// });// th.Start();//}//通过反射,破解单例设计模式//Assembly(获取要反射的程序集DLL--->Class Method INterface Delegate Event。。。。) TypeType type = typeof(LazyManClass);ConstructorInfo[] ci = type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);//正常的调用静态方法创建对象//LazyManClass lazyManClass = LazyManClass.GetLazyMan();//ci[0]就是私有的构造函数//通过调用私有的构造函数,跳过判断,直接创建对象LazyManClass l1 = (LazyManClass)ci[0].Invoke(null);//在第二次创建对象之前,获取b的值,重新修改为falseFieldInfo fi = type.GetField("b", BindingFlags.NonPublic | BindingFlags.Static);//修改字段的值//参数1:要修改的字段//参数2:修改后的值fi.SetValue(fi, false);LazyManClass l2 = (LazyManClass)ci[0].Invoke(null);fi.SetValue(fi, false);LazyManClass l3 = (LazyManClass)ci[0].Invoke(null);fi.SetValue(fi, false);LazyManClass l4 = (LazyManClass)ci[0].Invoke(null);Console.WriteLine(l1.GetHashCode());Console.WriteLine(l2.GetHashCode());Console.WriteLine(l3.GetHashCode());Console.WriteLine(l4.GetHashCode());Console.ReadKey();}}class LazyManClass{private LazyManClass(){if (b == false){b = true;}else{throw new Exception("有人破坏单例设计模式!!!!!");}//if (_lazyManClass != null)//{// throw new Exception("有人破坏单例设计模式!!!!!");//}Console.WriteLine("我被创建了一次");}private static LazyManClass _lazyManClass = null;private static object o = new object();private static bool b = false;public static LazyManClass GetLazyMan(){if (_lazyManClass == null){lock (o){if (_lazyManClass == null){return _lazyManClass = new LazyManClass();}}}return _lazyManClass;}}
基于Task的异步编程模型
internal class Program{static async Task Main(string[] args){//以同步的方式,开发异步的代码//下载一个网页的数据---->写入到指定的路径下//异步会传染//异步方法的返回值类型必须放到Task<T>中 ,如果没有返回值,则写Task---->void Task<int> intConsole.WriteLine("Main函数调用异步方法之前的线程" + Thread.CurrentThread.ManagedThreadId);int r = await DownHTML_WriteFile("http://www.taobao.com", @"C:\Users\ThinkPad\Desktop\abcabc.txt");Console.WriteLine("Main函数调用异步方法之后的线程" + Thread.CurrentThread.ManagedThreadId);Console.WriteLine("数据的长度是{0}", r);Task 底层就是线程池//Task task = new Task(() =>//{// Console.WriteLine("开始了一个任务");//});//task.ContinueWith((t) =>//{// Console.WriteLine("我是任务1");// Console.WriteLine(Thread.CurrentThread.ManagedThreadId);//}).ContinueWith((t) =>//{// Console.WriteLine("我是任务2");// Console.WriteLine(Thread.CurrentThread.ManagedThreadId);//}).ContinueWith((t) => {// Console.WriteLine("我是任务3");// Console.WriteLine(Thread.CurrentThread.ManagedThreadId);//});//task.Start();//Task.Run(() =>//{// Console.WriteLine("开始了一个任务");//});//Task.Factory.StartNew(() => {// Console.WriteLine("开始了一个任务");//});//任务:I/O密集型 Input/OutPut------>写入一个文件 读取一个文件 读取一个数据 写入一个数据库 //任务: 计算密集型Console.ReadKey();}//Task:异步执行的任务//async 异步方法 [MehodImp(。。。。。sync....)]//await 等待异步方法执行后的结果static async Task<int> DownHTML_WriteFile(string url, string path){//状态机设计模式WebClient wc = new WebClient();Console.WriteLine("开始异步任务1之前的线程是" + Thread.CurrentThread.ManagedThreadId);//DownloadStringTaskAsync :基于任务的异步方法Task<string> task = wc.DownloadStringTaskAsync(url);string htmlStr = await task; //等待任务执行---->开启一个新线程----->等待任务的执行Console.WriteLine("开始异步任务1之后的线程是" + Thread.CurrentThread.ManagedThreadId);//Console.WriteLine(htmlStr);using (FileStream fsWrite = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write)){byte[] buffer = Encoding.Default.GetBytes(htmlStr);Console.WriteLine("开始异步任务2之前的线程是" + Thread.CurrentThread.ManagedThreadId);//fsWrite.Write();同步方法await fsWrite.WriteAsync(buffer, 0, buffer.Length); //又开了一个新线程Console.WriteLine("开始异步任务2之后的线程是" + Thread.CurrentThread.ManagedThreadId);}//把数据的长度返回return htmlStr.Length;}}
Winform中的异步
public partial class Form1 : Form{public Form1(){InitializeComponent();}//EventHandler void object EventArgs//void:winform中事件的void,不许修改。可以标记为async,但是不能修改。private async void button1_Click(object sender, EventArgs e){int n = await DownHTML_WriteFile("a", "b");}static async Task<int> DownHTML_WriteFile(string url, string path){WebClient wc = new WebClient();Console.WriteLine("开始异步任务1之前的线程是" + Thread.CurrentThread.ManagedThreadId);//DownloadStringTaskAsync :基于任务的异步方法Task<string> task = wc.DownloadStringTaskAsync(url);string htmlStr = await task; //等待任务执行---->开启一个新线程----->等待任务的执行Console.WriteLine("开始异步任务1之后的线程是" + Thread.CurrentThread.ManagedThreadId);//Console.WriteLine(htmlStr);using (FileStream fsWrite = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write)){byte[] buffer = Encoding.Default.GetBytes(htmlStr);Console.WriteLine("开始异步任务2之前的线程是" + Thread.CurrentThread.ManagedThreadId);//fsWrite.Write();同步方法await fsWrite.WriteAsync(buffer, 0, buffer.Length); //又开了一个新线程Console.WriteLine("开始异步任务2之后的线程是" + Thread.CurrentThread.ManagedThreadId);}//把数据的长度返回return htmlStr.Length;}}
七大设计原则
单一职责原则
应该有且只有一个引起类变更的原因。一个类,只负责一件事
好处:
1、提高了代码的可读性,提高系统的可维护性
2、降低类的复杂性,一个模块只负责一个职责,提高系统的可扩展性和可维护性
3、降低变更引起的风险。变更时必然的,如果单一职责做的好,当修改一个功能的时候可以显著的降低对另一个功能的影响
{internal class Program{static void Main(string[] args){//Dial//HangUp//SendMessage//ReciveMessageTelPhone tel = new TelPhone();tel.Dial = new DialClass(); //new DialMindClass();tel.Tel_Dial();Console.ReadKey();}}interface IDial{void Dial();}class DialClass:IDial{public void Dial(){Console.WriteLine("使用按键拨打电话");//使用意念拨打电话}}class DialMindClass:IDial{public void Dial(){Console.WriteLine("意念拨打电话");}}interface IHangUp{void HangUP();}class HangUpClass:IHangUp{public void HangUP(){Console.WriteLine("使用按键,挂断电话");}}interface ISendMessage{void SendMessage();}class SendClass: ISendMessage{public void SendMessage(){Console.WriteLine("发送短信");}}interface IRecMessage{void ResMsg();}class RecClass:IRecMessage{public void ResMsg(){Console.WriteLine("接收短信");}}class TelPhone //引起类变更的原因,只有一个{//外部的变化:客观存在的。//内部的变化://导入依赖//public DialClass Dial { get; set; }//public HangUpClass HangUP { get; set; }//public SendClass SendMessage { get; set; }//public RecClass RecMessage { get; set; }//public DialMindClass DialMind { get; set; }//面向接口编程------->面向抽象编程 ---->【封装变化】 --->最少的代码,写出最通用的功能 ---->高内聚、低耦合--->可扩展public IDial Dial { get; set; }public IHangUp HangUp { get; set; }public ISendMessage SendMessage { get; set; }public IRecMessage RecMessage { get; set; }//开闭原则:对扩展开放,对修改关闭public void Tel_Dial(){this.Dial.Dial();}public void Tel_HangUp(){this.HangUp.HangUP();}public void Tel_Send(){this.SendMessage.SendMessage();}public void Tel_Rec(){this.RecMessage.ResMsg();}}}
开放封闭原则(OCP)
1、开放封闭原则是面向对象所有原则的核心
2、对功能扩展开放;对修改代码封闭
3、需求改变时,在不改变软件实体源代码(类、接口、方法等)的前提下,通过扩展功能,使其满足新的需求
使⽤代码,描述不同需求的⽤户去银⾏办理不同的业务
{internal class Program{static void Main(string[] args){//不同需求的用户,去银行找柜员办理业务 银行处理系统Client client = new Client() { Purpose = "存钱" };BankStuff bankStuff = new BankStuff();BankProcess bankProcess = new BankProcess();bankStuff.BankProcess = bankProcess;bankStuff.ProcessClient(client);Console.ReadKey();}}//不同需求的用户class Client{public string Purpose { get; set; }}//银行柜员class BankStuff{public BankProcess BankProcess { get; set; }//调用银行处理系统,处理用户的需求public void ProcessClient(Client client){//判断用户的需求//switch是一定不符合开闭的原则代码,你的程序中,只要出现了switch或者if elseif之类的多条件判断 OCP//shit Mountain 屎山switch (client.Purpose){case "存钱":this.BankProcess.CunMoney();break;case "取钱":this.BankProcess.QuMoney();break;default:Console.WriteLine("无法处理您的需求");break;}}}//银行处理系统class BankProcess{public void CunMoney(){Console.WriteLine("处理存钱");}public void QuMoney(){Console.WriteLine("处理取钱");}}}
银行办理业务2.0
{internal class Program{static void Main(string[] args){Client c = new Client() { Purpose = "取钱" };BankStuff bankStuff = new BankStuff();BankProcess bankProcess = new BankProcess();bankStuff.BankProcess = bankProcess;bankStuff.ProcessClient(c);Console.ReadKey();}}//不同需求的用户class Client{public string Purpose { get; set; }}class BankStuff{public BankProcess BankProcess { get; set; }//调用银行处理系统,处理用户的需求public void ProcessClient(Client client){//判断用户的需求//switch是一定不符合开闭的原则代码,你的程序中,只要出现了switch或者if elseif之类的多条件判断 OCP//shit Mountain 屎山switch (client.Purpose){case "存钱"://this.BankProcess.CunMoney();this.BankProcess.CunMoney = new CunClass();this.BankProcess.Cun();break;case "取钱":this.BankProcess.QuMoney = new QuClass();this.BankProcess.Qu();//this.BankProcess.QuMoney();break;default:Console.WriteLine("无法处理您的需求");break;}}}interface ICunMoney{void CunMoney();}class CunClass : ICunMoney{public void CunMoney(){Console.WriteLine("处理存钱");}}interface IQuMoeny{void QuMoney();}class QuClass : IQuMoeny{public void QuMoney(){Console.WriteLine("处理取钱");}}interface IBuyJJ{void BuyJJ();}class BuyClass: IBuyJJ{public void BuyJJ(){Console.WriteLine("买基金");}}class BankProcess{public ICunMoney CunMoney { get; set; }public IQuMoeny QuMoney { get; set; }public IBuyJJ BuyJJ { get; set; }public void Cun(){this.CunMoney.CunMoney();}public void Qu(){this.QuMoney.QuMoney();}public void Buy(){this.BuyJJ.BuyJJ();}}}
依赖倒置原则
开放封闭原则是面向对象设计的终极目标,而依赖倒置原则是实现开放封闭原则的基础
如果开放封闭原则是设计大楼的蓝图,那么依赖倒置原则就是大楼的钢铁架构
1、高层模块(调用者)不应该依赖于低层模块(被调用者),两个都应该依赖于抽象
2、抽象不应该依赖细节,细节应该依赖于抽象
3、依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,互不影响,实现模块间的松耦合
{internal class Program{static void Main(string[] args){//歌手歌唱不同国家的歌曲Singer singer = new Singer();singer.SingingChinese(new ChineseSong());singer.SingingChinese(new JapanSong());Console.ReadKey();}}interface ISong{string SingingASong();}class ChineseSong:ISong{public string SingingASong(){return "中国歌曲";}}class KoreaSong:ISong{public string SingingASong(){return "思密达";}}class JapanSong:ISong{public string SingingASong(){return "aligaduo";}}class Singer //调用者{//调用者和被调用者,强耦合----->//使用抽象【接口/抽象类】封装变化//抽象不应该依赖细节,细节应该依赖于抽象 面向抽象编程public void SingingChinese(ISong cs) //被调用者{Console.WriteLine("正在唱"+cs.SingingASong());}// 通过抽象,使各个模块或者类的实现彼此独立,互不影响,实现模块间的松耦合}}
关于依赖:
1、一个优秀的面向对象程序设计,核心的原则之一就是将变化隔离(封装),使变化部分发生变化时,其他部分不受影响
2、为了实现这个目的,需要使用面向接口编程。使用后,客户类不再直接依赖于服务类,而是依赖一个抽象的接口。这样,客户类就不能在内部直接实例化服务类
3、但是客户类在运行的过程中,又需要具体的服务类来提供服务,因为接口是不能实例化的,就产生了一个矛盾:客户类不允许实例化服务类,但是客户类又需要服务类的服务
4、为了解决这个矛盾,我们设计了一种解决方案,既:客户类注定义一个注入点,用于服务类的注入,而客户类的客户类(Program类)负责根据情况,实例化服务类,注入到客户类中,从而解决了这个矛盾
依赖关系如何传递?(依赖注入)
1、通过接口传递(接口注入)
2、通过构造方法传递
3、通过属性的Set方法传递
里氏替换原则
1、如果S是T的子类型,则T类型的对象可以替换为S类型的对象
2、所有引用父类对象的地方,都可以使用其子类型代替
3、子类可以替换父类
接口分离原则
1、客户端不应该依赖它不需要的接口
2、一个类对另一个类的依赖应该建立在最小接口上
3、接口尽量细分,不要在一个接口中放很多方法
{internal class Program{static void Main(string[] args){}}interface IScore{//修改某个学生的成绩void ChangeScore();//void Login();}//1、接口要符合高内聚//2、接口要符合单一职责原则//3、还要考虑实现类权限的问题,对接口中的方法进行分类细分。interface ISuperScore{//添加某个学生的成绩void AddScore();//删除某个学生的成绩void DeleteScore();}interface IQueryScore{void QueryScore();}class Teacher : IScore,IQueryScore{public void AddScore(){throw new NotImplementedException();}public void ChangeScore(){throw new NotImplementedException();}public void DeleteScore(){throw new NotImplementedException();}public void QueryScore(){throw new NotImplementedException();}}class Student : IQueryScore{public void QueryScore(){throw new NotImplementedException();}}
}
迪米特原则(最小知识原则)
1、它要求一个对象应该对其他对象有最少的了解
2、降低类之间的耦合
3、迪米特原则实际上就是一个类在创建方法和属性时要遵守的原则(只和直接朋友通信)
直接朋友:
1、成员对象
2、方法参数
3、方法返回值
4、注意:出现在局部变量中的类,不是直接朋友
{internal class Program{static void Main(string[] args){//总公司员工类 :ID//总公司员工管理类//1、添加总公司员工//2、打印总公司每个员工//3、打印分公司每个员工//分公司员工类 :ID//分公司员工管理类//1、添加分公司员工HeadEmployeeManager headEmployeeManager = new HeadEmployeeManager();headEmployeeManager.PrintEmployees();Console.ReadKey();}}//总公司员工类 天高皇帝远class HeadEmployee{public int ID { get; set; }}//总公司员工管理类//谁是HeadEmployeeManager的直接朋友//成员对象 方法的参数类型 方法的返回值类型//List<HeadEmployee> listHeadEmployee 直接朋友//List<HeadEmployee> 直接朋友//BodyEmployeeManager bodyEmployeeManager 不是直接朋友// List<BodyEmployee> listBodyEmployees 不是直接朋友class HeadEmployeeManager{//总公司员工集合private List<HeadEmployee> listHeadEmployee = new List<HeadEmployee>();//添加总公司员工public List<HeadEmployee> AddHeadEmployees(){for (int i = 0; i < 10; i++){listHeadEmployee.Add(new HeadEmployee() { ID = i + 1 });}return listHeadEmployee;}//打印总公司员工和分公司员工public void PrintEmployees(){this.AddHeadEmployees();Console.WriteLine("==========================以下是总公司员工ID=====================================================");//打印总公司员工for (int i = 0; i < listHeadEmployee.Count; i++){Console.WriteLine(listHeadEmployee[i].ID);}Console.WriteLine("==========================以下是分公司员工ID=====================================================");//3、打印分公司每个员工//3.1 创建分公司员工管理类的对象BodyEmployeeManager bodyEmployeeManager = new BodyEmployeeManager();//3.2 调用AddBodyEmployee添加分公司成员,并获取返回值List<BodyEmployee> listBodyEmployees = bodyEmployeeManager.AddBodyEmployees();//3.3 循环分公司员工的集合for (int i = 0; i < listBodyEmployees.Count; i++){Console.WriteLine(listBodyEmployees[i].ID);}}}class BodyEmployee{public int ID { get; set; }}class BodyEmployeeManager{private List<BodyEmployee> listBodyEmployee = new List<BodyEmployee>();public List<BodyEmployee> AddBodyEmployees(){for (int i = 0; i < 5; i++){listBodyEmployee.Add(new BodyEmployee() { ID = i + 1 });}return listBodyEmployee;}}}
合成复用原则
1、合成复用原则,又称组合\聚合复用原则
2、尽量使用对象组合,而不是继承来达到复用
3、继承的问题:a、破坏了系统的封装性,基类发生了变化,子类的实现也会发生变化
b、继承是静态的,不能在程序运行时发生变化
4、合成复用原则是将已有的对象纳入到新对象中,作为新对象的对象成员来实现的,新对象可以调用已有对象的功能,从而达到复用
类与类之间的关系:泛化、实现、组合、聚合、关联、依赖
泛化:Animal是Tiger的泛化,Tiger是Animal的特化
实现:类与接⼝的关系,表示类实现了接口
组合:组合是整体和部分的关系,部分没有独⽴的⽣命周期,组合是把部分作为整体类的对象
聚合:聚合也是整体与部分的关系,但是个体有独⽴的⽣命周期,聚合是把个体对象的指针(引⽤)作为整体类的属性
关联:关联是⼀种拥有关系,它使⼀个类知道另⼀个类的属性和⽅法。
依赖:依赖是一种使用关系
类与类之间的关系
{internal class Program{static void Main(string[] args){}}class Animal //泛化{public char Gender { get; set; }public void Eat(){Console.WriteLine("动物都能吃");}public void Sleep(){Console.WriteLine("动物都能睡觉");}}class Tiger:Animal ,IClimb //特化{//Tiger和Leg是组合关系,强拥有关系,两个对象的生命周期必须是一样的。public Leg Legs { get; set; }//在老虎的构造函数中,传入Leg的对象,表示Tiger跟Leg同时出生。public Tiger(Leg leg){this.Legs = leg;}//属性注入、构造注入、传参注入//关联public Food Food { get; set; }//依赖public Water Water { get; set; }public string Name { get; set; }public void Climb(){Console.WriteLine("老虎会爬树");}}class Food{public string Name { get; set; }public string Color { get; set; }}class Water{public double Weight { get; set; }}class TigerGroup{//聚合关系public Tiger[] Tigers { get; set; }}class Leg{public int Count { get; set; }}interface IClimb{void Climb();}
}
合成复用原则
{internal class Program{static void Main(string[] args){//继承问题://1、可能会造成子类功能泛滥//2、可能会造成子类数量爆炸//3、打破了类的封装性 //sealed B:A //创建油车对象YouCar youCar = new YouCar(new Blue());youCar.Move();Console.ReadKey();}}interface IColor{string GetColor();}class White : IColor{public string GetColor(){return "白色";}}class Red : IColor{public string GetColor(){return "红色";}}class Blue : IColor{public string GetColor(){return "蓝色";}}abstract class Car{public IColor Color { get; set; }public Car(IColor color) //组合,强拥有关系{this.Color = color;}public abstract void Move();}class DianCar : Car{public DianCar(IColor color) : base(color){ }public override void Move(){//是什么颜色的电动汽车在跑Console.WriteLine(this.Color.GetColor() + "的电动汽车,工业垃圾,在用电奔跑"); //发动机、底盘、变速箱}}class YouCar : Car{public YouCar(IColor color) : base(color){ }public override void Move(){//是什么颜色的电动汽车在跑Console.WriteLine(this.Color.GetColor() + "汽油车再用油奔跑"); //发动机、底盘、变速箱}}}
设计原则总结
1、设计原则是「高内聚、低耦合」的具体落地。
2、单一职责原则要求在软件系统开发、设计中,一个类只负责一个功能领域的相关职责。
3、开放封闭原则要求一个软件应该对扩展开放,对修改封闭,即在不修改源代码的情况下,完成系统功能的扩展。
4、里式替换原则决定了子类可以赋值给父类,
5、依赖倒置原则要求抽象不应该依赖于细节,细节应该依赖于抽象。要面向接口编程,不要面向实现编程。
6、迪米特原则要求一个对象尽可能少的与其他对象发生相互作用。
7、接口隔离原则要求客户端不应该依赖那些他不需要的接口,即将一些大的接口细化成一些小的接口供客户端使用。
8、合成复用原则要求我们尽量使用对象的组合,而非继承来达到复用的目标。