通过反射,破坏单例设计模式
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。。。。) Type
Type 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的值,重新修改为false
FieldInfo 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> int
Console.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
//ReciveMessage
TelPhone 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、合成复用原则要求我们尽量使用对象的组合,而非继承来达到复用的目标。