#Day01 2024.05.10

今日总结:

  1. 什么是索引器,怎么用
  2. 语法糖foreach的底层原理
  3. 泛型的学习
  4. 委托
  5. Lambda
  6. 委托实例—窗体传值

索引器

  • 数组或者集合内部默认就有索引器(C#),因此我们才可以默认使用【下标】的形式,访问他们中内部的某一元素
  • 但是,我们自己定义的普通类中,默认是没有索引器的,如果我们想使用索引/下标的形式,访问对象集合中的某一元素则需要我们自己给类定义一个索引器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 索引器
{
internal class Program
{
static void Main(string[] args)
{
Student student = new Student();

Console.WriteLine(student[1]);

Console.WriteLine(student["张三"]);
//自定义索引器不仅可以根据数字索引,还可以根据字符串索引
//总而言之言而总之,索引器可以根据自身的需要决定用途
Console.ReadKey();
}
}
class Student
{
//可以是单个类型的数组
private string[] _studentNames = { "周杰伦", "林俊杰", "伍佰", "凤凰传奇", "迈克尔杰克逊" };

//定义索引器
public string this[int Index]
{
get { return _studentNames[Index]; }
set { _studentNames[Index] = value; }
}

//也可以是键值对
private Dictionary<string, int> DicStudent = new Dictionary<string, int>();
public int this[string str]
{
get { return DicStudent[str]; }
set { DicStudent[str] = value; }
}
//给键值对初始化
public Student()
{
DicStudent.Add("张三", 4);
DicStudent.Add("李四", 3);
DicStudent.Add("王五", 5);
}
}

}

索引器案例实写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _02索引器案例
{
internal class Program
{
static void Main(string[] args)
{
//员工类:姓名、员工号、部门名称
//1、根据员工的姓名、员工号,查找对方所在部门
//2、根据员工的姓名、部门名称,查找对方的员工号
//3、根据员工的员工号和部门名称,查找对方的姓名

EmpIndexor empi = new EmpIndexor();
string party = empi["张无忌", 23];
if(!string.IsNullOrEmpty(party) )
{
Console.WriteLine(party);
}
else
{

Console.WriteLine("查无此人!!!!!!");
}

string name = empi[14, "蛇精"];
if (!string.IsNullOrEmpty(name))
{
Console.WriteLine(name);
}
else
{

Console.WriteLine("查无此人!!!!!!");
}
Console.ReadKey ();
}

}
//
class Employee
{
public string Name { get; set; }
public int ID { get; set; }
public string Party { get; set; }

public Employee(string name,int id,string party)
{
this.Name = name;
this.ID = id;
this.Party = party;
}
}

class EmpIndexor
{
private List<Employee> EmpList = new List<Employee>();
//1、根据员工的姓名、员工号,查找对方所在部门
public string this[string name,int id]
{
get
{
for(int i = 0;i < EmpList.Count;i++)
{
if (EmpList[i].Name == name && EmpList[i].ID == id) return EmpList[i].Party;
}
return null;
}
}

//2、根据员工的姓名、部门名称,查找对方的员工号

public int? this[string name,string party]
{
get
{
for(int i = 0;i < EmpList.Count; i++)
{
if (EmpList[i].Name == name && EmpList[i].Party == party) return EmpList[i].ID;
}
return null;
}
}
//3、根据员工的员工号和部门名称,查找对方的姓名
public string this[int ID,string party]
{
get
{
for(int i = 0;i < EmpList.Count;i ++)
{
if (EmpList[i].ID == ID && EmpList[i].Party == party) return EmpList[i].Name;
}
return null;
}
}


public EmpIndexor()
{
EmpList.Add(new Employee("张无忌",23,"光明顶"));
EmpList.Add(new Employee("法海",29,"佛教"));
EmpList.Add(new Employee("许仙",25,"凡人"));
EmpList.Add(new Employee("小青",18,"蛇精"));
EmpList.Add(new Employee("白素贞",19,"蛇精"));
}
}
}

如何实现自定义类的foreach

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _03foreach
{
internal class Program
{
static void Main(string[] args)
{
//各种类型的数组能够被foreach本质上是实现了IEnumrator
//如果我们的自定义类要可以被foreach,就要实现IEnumrator

Person person = new Person();

//foreach(var item in person)
//{
// Console.WriteLine(item);
//}
//Console.ReadKey();

//1、创建一个迭代器对象
//2、迭代器对象获取到了要迭代的数据
IEnumerator itor = person.GetEnumerator();

while (itor.MoveNext())
{
Console.WriteLine(itor.Current);
}
Console.ReadKey();


}
}
//IEnumerator:实现foreach
//IEnumberable:接口,可以被foreach

class Person : IEnumerable
{
private string[] names = { "张无忌", "周杰伦", "伍佰", "张三丰", "乔峰" };
//Person类已经实现了IEnumerable接口,
//因此Person类可以获取一个迭代器对象,对自己集合元素进行迭代
public IEnumerator GetEnumerator()
{
return new PersonEnumerator(names);
}
}
/// <summary>
/// 迭代器类,迭代器设计模式
/// </summary>
class PersonEnumerator : IEnumerator
{
//要想实现遍历就得依赖注入
private string[] mynames { get; set; }

public PersonEnumerator(string[] names)//构造函数注入
{
this.mynames = names;
}
//Current属性表示返回当前遍历到的元素
public object Current
{
get
{
if(i < mynames.Length)
{
return mynames[i];
}
return null;
}
}
int i = -1;
public bool MoveNext()//实现向下一个元素遍历
{
if(i++ + 1 < mynames.Length)
{

return true;
}
return false;
}

public void Reset()
{
i = -1;
}
}
}

泛型的学习

  • 泛型的应用场景非常广泛
    1. 类可以使用泛型
    2. 接口可以使用泛型
    3. 方法可以使用泛型
  • 正因如此,泛型的约束也是重点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _06泛型约束
{
internal class Program
{
static void Main(string[] args)
{
//值类型、引用类型
//select * from student where ssex = '男';

//Person<string> person = new Person<string>();
Person<int> person = new Person<int>();

Student<Person<int>> student = new Student<Person<int>>();

Teacher<Animal> teacher = new Teacher<Animal>();
Teacher<Bird> teacher2 = new Teacher<Bird>();

//Teacher<string> teacher3 = new Teacher<string>();


Driver<Sprraw> dirver1 = new Driver<Sprraw>();
Driver<IFlyable> driver2 = new Driver<IFlyable>();
//Driver<string> driver3 = new Driver<string>();


//Computer<int, string> cpu = new Computer<int, string>();

Computer<int, IComparable> cpu = new Computer<int, IComparable>();

Computer<Bird, Animal> cpu2 = new Computer<Bird, Animal>();
}
}

class Person<T> where T : struct { } //约束类型T必须是一个值类型


class Student<T> where T : class ,new(){ }
//约束类型T必须是一个引用类型,new() 表示类型必须具备无参数的构造函数,且new()必须在最后面

class Animal { }

class Bird:Animal { }

class Teacher<T> : Animal { }//Teacher的约束类型T必须是Animal或者Animal的子类

interface IFlyable { };

class Sprraw: IFlyable { }
class Driver<T> where T : IFlyable { }//Driver的约束类型T必须是IFlyable或者是继承了IFlyable接口的类

class Computer<T,U> where T : U { }//Computer的约束类型T必须是U的子类(此时U是一个类)或者是实现了
//U的类(此时U是一个接口)
}

Lambda表达式

1
()

委托

委托的封装好的用法

  • 概念:委托就是把一个方法作为参数,传递给另一个方法的技术,可以理解委托是方法的指针(在窗体值传递案例中最为明显)

  • 委托可以理解为起来两个概念

    1. 方法的数据类型(因此我们要注意:委托的签名【返回值和参数】必须跟它指向的方法的签名,保持一致)
    2. 指向方法的指针
  • 都没有封装之后的用法

  • 封装之后的用法(泛型委托)

    1. Action:封装好的无返回参数的委托
    2. Func:封装好的有一个返回参数的委托
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 委托
{
internal class Program
{
static void Main(string[] args)
{
//C#内置了两个委托
//Action、Func

Action action = () => { Console.WriteLine("此委托没有返回值"); };
action();
//Func中最后一个类型值是返回值的类型(这里是string)
Func<int, int, string> func = (n, m) =>
{
return (n + m).ToString();
};

string s = func(100, 89347);
Console.WriteLine(s);
Console.ReadKey();
}
}
}

使用委托实现窗体传值

使用委托传值需要依赖注入,一般使用的方法就是构造函数注入

Form1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace _13_使用委托实现窗体传值
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
Form2 frm2 = new Form2(textBox1.Text.Trim(),ShowMsg);
frm2.Show();
}

//窗体1,有给文本框赋值的方法,但是没有值
void ShowMsg(string str)
{
//把字符串赋值给窗体1的文本框
textBox1.Text = str;
}

private void textBox1_TextChanged(object sender, EventArgs e)
{

}

private void Form1_Load(object sender, EventArgs e)
{

}
}
}

Form2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace _13_使用委托实现窗体传值
{
public delegate void DelShowMsg(string str);
public partial class Form2 : Form
{
private DelShowMsg delShowMsg;

//泛型委托版
private Action<string> _action;

public Form2(string str, Action<string> action)
{
this._action = action;
InitializeComponent();
textBox1.Text = str;
}

//public Form2(string str, DelShowMsg del)
//{
// this.delShowMsg = del;
// InitializeComponent();
// textBox1.Text = str;
//}

private void button1_Click(object sender, EventArgs e)
{
string str= textBox1.Text;
//窗体2有值,但是没有给窗体1赋值的方法
//delShowMsg(str);
_action(str);
}

private void Form2_Load(object sender, EventArgs e)
{

}
}
}

#Day02 2024.05.11

反射常用方法


反射就是动态获取数据集的源数据

  1. Type使用(操作类的
  2. Assembly使用(操作数据集的

Type使用

  1. 在不创建Person对象的情况下,获取type

    Type type = typeof(Person)

  2. 在创建对象的情况下,获取type

    Person p = new Person()

    Type type2 = p.GetType()

GetMembers():获取类型中所有的成员

1
2
3
4
MemberInfo[] mems = type.GetMembers();//获取type类型中所有的公开成员(包括继承的
//获取私有的实例字段(成员)
//GetMembers()有两个筛选条件,第一个筛选实例或者静态,第二个筛选公开还是私有
MemberInfo[] mems = type.GetMembers(BindingFlags.Instance | BindingFlags.Nonpublic);

GetMethods():获取类型中所有的方法

Getparameters():获取类型的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
MethodsInfo[] mi = type.GetMethods();//获取type类中所有的公开方法
//获取方法以后,我们还得使用方法
//使用方法我们就得知道方法是实例的还是静态的、
foreach(var item in mi){
Console.WriteLine(item.Name);
ParameterInfo[] param = item.GetParamrters();
foreach(vae item2 in param){
Console.WritwLine(item2.parapeterType)
}
}
//1、实例还是静态很好区分,筛选的时候加上BindingFlags.Static就行
//2、使用Getparameter()获取参数
//这样的话就可以使用GetMethods()获取到的方法了

GetPropertites():获取类型中所有属性

1
PropertyInfo[] pros = type.getProperties();

GetConstrutors获取类型中的构造函数

1
ConstructorInfo[] ci = type.GetConstructor();

GetFields():获取类型中的所有字段

1
FieldInfo[] fi = type.GetFields();

Assembly使用

Assembly.LoadFile(path) :获取path路径下的dll文件(程序集对象

ass.GetTypes():获取所有自定义的类型

Activator.Greateinstance(type):动态地创建对象(只需要知道对象的名称)返回object

type.GetConstructor:调用构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Assembily ass = Assembly.LoadFile(path);
Types[] types = ass.getTypes();
Types[] types = ass.GetExportedTypes();//获取该程序集(dll)中向外暴露的类
//GetType获取指定数据类型的时候,必须加上命名空间
Type type = ass.Gettype("ClassLibrary.Person");//获取指定的自定义的数据类型

MethodInfo mi = type.GetMethod("InstanceMethod");
object o = Activator.CteateInstance(type);
mi.Invoke(o,null);//mi(o,null);

//调用重载的方法
MethodInfo mi = type.GetMethod("Add",new Type[] { typeof(int),typeof(int)});//Add在这里被重载了,因此在GetMethod的时候就要分清楚GET到的是哪个Add
object o = Activator.CteateInstance(type);
mi.Invoke(o,new object[] { 1, 1});

ConstructorInfo ci = type.GetConstructor(new type[] {})//构造函数默认重载,需要哪个就在type[]里面添加参数
object o = ci.Invoke(null);//构造函数执行完的返回值一定是实例对象
Consol.Writeline(o.GteType());//获取类型

插件的制作

插件的制作过程如下

  1. 创建一个【解决方案文件夹】
  2. 创建窗体程序
  3. 创建规范接口文件
    • 确定是接口还是抽象类
    • 确定属性、方法、构造函数(抽象类才需要)
  4. 创建实现插件功能的类库
    • 需要生成的 dll 文件
  5. 将所有的dll文件放在指定的文件夹中
  6. Form窗体Load中实现插件功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//记事本差劲程序--窗体代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Plug_in_Components_Rule;
namespace _05_记事本插件应用程序
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
//程序加载的时候,读取我所有的插件
//绝对路径:电脑上的路径 c:\。。。。。。
//相对路径:相对于程序的路径

//获取插件存放的文件夹路径
string path = Assembly.GetExecutingAssembly().Location;
path = Path.GetDirectoryName(path);
path = Path.Combine(path, "Plug_in_Componets");
//去文件夹中,读取所有的插件
string[] filePath = Directory.GetFiles(path);
//使用Assembly加载所有的插件
foreach (string item in filePath)
{
//ass :DLL ToUPPer
Assembly ass = Assembly.LoadFile(item);
//class 抽象类 接口 事件、委托.....
Type[] types = ass.GetExportedTypes();
foreach (var item2 in types)
{
//跟规范有一个实现关系,并且不能是抽象的
if (typeof(Plug_in_Rule).IsAssignableFrom(item2) && !item2.IsAbstract)
{
//动态的创建了插件对象
object o = Activator.CreateInstance(item2);
//把对象,直接转换为接口
Plug_in_Rule pir = (Plug_in_Rule)o;
//已经获取到了StrToUpper
ToolStripItem tsi = menuStrip1.Items.Add(pir.Name);
//给tsi添加一个单击事件
tsi.Click += Tsi_Click;
//把接口,传递给Tsi_Click事件
tsi.Tag = pir;
}
}
}
}

/// <summary>
/// 单击的时候,要调用插件的方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Tsi_Click(object sender, EventArgs e)
{
//sender表示触发这个事件的对象,谁的事件,sender就是谁
//把sender转换为tsi对象
ToolStripItem tsi = (ToolStripItem)sender;
//在Load事件中,把接口封装到了tsi.Tag中,把Tag中的接口,再拿出来
Plug_in_Rule pir = (Plug_in_Rule)tsi.Tag;
//调用接口的方法------>执行的是指向接口的类的方法
pir.ChangeText(textBox1);
}
}
}

插件开发

开发者

  1. 插件开发的规范(接口/抽象类)
  2. 单独的写一个程序读取所有的插件,把功能绑定到自己的程序中

插件开发者

  1. 照着开发的规范,实现功能的拓展

#Day03 2024.05.12

今日知识点

  1. 事件:概念、组成元素
  2. 多播委托(不安全
  3. 事件(安全
  4. 自创组件
  5. 委托、事件和反射面试必问,一定得好好总结!!!
  6. 递归

事件

概念:事件就是一个类型安全的委托

组成元素

  1. 注册事件
  2. 触发事件
  3. 响应事件

多播委托

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public delegate void del();//定义一个无参数无返回值的委托
del d = m1;

d += m2;
d += m3;
d += m4;
d();//结果是
/*
我是m1
我是m2
我是m3
我是m4
*/
static void m1 {
Console.WriteLine("我是m1");
}
static void m2 {
Console.WriteLine("我是m2");
}
static void m3 {
Console.WriteLine("我是m3");
}
static void m4 {
Console.WriteLine("我是m4");
}

事件

概念:事件就是一个【类型安全】的委托

为什么可以用委托模拟事件使用事件和使用委托,过程是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace 委托模拟事件
{
internal class Program
{
static void Main(string[] args)
{
MusicPlayer mp = new MusicPlayer();
//注册事件
mp.BeforeMusic = () => { Console.WriteLine("1、检测该歌曲是否为会员歌曲。2、检测登录成员是否为会员。3、是否从数据库中调取歌词"); };//把开始播放音乐之前的是交给用户去写
mp.AfterMusic = () => { Console.WriteLine("1、 检测当前播放是什么播放模式。2、按照播放模式播放下一首歌曲。"); };
mp.StartMusic();
mp.Stop();
Console.ReadKey();
}
}

class MusicPlayer
{
//为什么采用这种结构
//因为我们只应该留给用户点击开始接口和结束播放接口
//其余的不应该暴露给外界

//现在我们将开始播放前要做的事儿暴露给用户
public Action BeforeMusic;
public Action AfterMusic;
private void Playing()
{
//1、检测该歌曲是否为会员歌曲。
//2、检测登录成员是否为会员。
//3、是否从数据库中调取歌词
this.BeforeMusic();//执行事件
Console.WriteLine("正在播放音乐。。");
}
public void StartMusic()//触发事件
{
//BeforeMusic();
Console.WriteLine("开始播放音乐");
this.Playing();
Thread.Sleep(3000);
}
public void Stop()//触发事件
{
Console.WriteLine("结束播放音乐");
this.AfterMusic();//执行事件
}

//public void BeforeMusic()
//{
// Console.WriteLine
// ("1、检测该歌曲是否为会员歌曲。2、检测登录成员是否为会员。3、是否从数据库中调取歌词");
//}
//public void AfterMusic()
//{
// Console.WriteLine
// ("1、 检测当前播放是什么播放模式。2、按照播放模式播放下一首歌曲。");
//}


}
}

自创组件

  1. 在创建类里面选择用户控件(每次更改后要重新生成
  2. 自定义

点击跳转

递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 递归加载所有文件夹和文件
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{

}

private void btn1_Click(object sender, EventArgs e)
{
//1、获取文本框内的路径
//2、顺序获取该路径下的全部文件
//2.1递归获取所有文件

//string path = txtPath.Text.Trim();
//path = $"@\"{path}\"";
//MessageBox.Show(path);

string path = @"E:\Aria2";

Recursion(path, treeView1.Nodes);

}

private void Recursion(string path,TreeNodeCollection treeNodes)
{
string[] fliePaths = Directory.GetDirectories(path);//获取文件夹下的所有文件名称(包括其路径

foreach (string paths in fliePaths)
{
TreeNode tn = treeNodes.Add(Path.GetFileName(paths));//获取paths路径下的文件(文件夹)名称
Recursion(paths, tn.Nodes);//递归
}

string[] files = Directory.GetFiles(path);

foreach (string paths in files)
{
treeNodes.Add(Path.GetFileName(paths));
}
}
}
}

#Day04 2024.05.14

今日知识点:

  1. XML
  2. 正则表达式

Xml

Xml文件路径默认保存在当前目录的Debug文件夹里面

  • 第一次使用CreateElement创建的结点为根节点,其后创建的结点都为子节点
  • 先创造属性后添加到结点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
XmlDocument xd = new XmlDocument();

List<Person> listPerson = new List<Person>();
listPerson.Add(new Person() { Name = "周杰伦", Age = 98, Gender = '男', ID = "1" });
listPerson.Add(new Person() { Name = "林俊杰", Age = 28, Gender = '男', ID = "2" });
listPerson.Add(new Person() { Name = "伍佰", Age = 38, Gender = '男', ID = "3" });
listPerson.Add(new Person() { Name = "周饼伦", Age = 48, Gender = '男', ID = "4" });
listPerson.Add(new Person() { Name = "王力宏", Age = 58, Gender = '男', ID = "5" });
listPerson.Add(new Person() { Name = "张杰", Age = 38, Gender = '男', ID = "6" });

//文档声明
XmlDeclaration dec = xd.CreateXmlDeclaration("1.0", "utf-8", null);
xd.AppendChild(dec);
//创建根节点
XmlElement Persons = xd.CreateElement("Persons");
xd.AppendChild(Persons);

foreach (Person person in listPerson)
{
//创建子节点
XmlElement Person = xd.CreateElement("Person");
Persons.AppendChild(Person);
//添加属性
XmlAttribute att = xd.CreateAttribute("ID");
att.Value = person.ID;
Person.Attributes.Append(att);
//加名字
XmlElement name = xd.CreateElement("Name");
name.InnerText = person.Name;
Person.AppendChild(name);
//加年龄
XmlElement age = xd.CreateElement("Age");
age.InnerText = person.Age.ToString();
Person.AppendChild(age);
//加性别
XmlElement gender = xd.CreateElement("Gender");
gender.InnerText = person.Gender.ToString();
Person.AppendChild(gender);
}

xd.Save("Profiles.xml");
Console.WriteLine("OK");
}
}

class Person
{
public string Name { get; set; }
public int Age { get; set; }
public char Gender { get; set; }
public string ID { get; set; }
}
}

正则表达式

基础概念

  1. .匹配单个字符(\n除外)
  2. []匹配括号里的任何一个字符
  3. |表示或运算
    • z|food为不完全匹配,所有含有z和food的字符串使用Regex.IsMatch返回都为true
    • (z|f)ood为不完全匹配,所有含有zood和food的字符串使用Regex.IsMatch返回都为true
      • ^z|food$为完全匹配,以z开头或者以food结尾的字符串使用Regex.IsMatch返回都为true
    • ^(z|food)$为完全匹配,只有z和food这两个字符串使用Regex.IsMatch返回为true
  4. *等价与{ 0 , },匹配0次或多次*号前面的单个字符
  5. +等价与{ 1, },匹配1次或多次+号前面的单个字符
  6. ?等价与{ 0, 1 },匹配0次或一次?号前面的单个字符
  7. {n}匹配n次{}前面的单个字符或字符组
  8. {n,m}至少匹配n次,至多匹配m次{}前面的单个字符或字符组
  9. ^匹配一行的开始
  10. $匹配一行的结束

进阶概念

  1. \d代表一个数字,等同于[0-9]———————–d => digital
  2. \D代表非数字,等同于[^0-9]
  3. \s代表换行符、tab制表符等空白字符————-s => space
  4. \S代表非空白字符(a0%$@等)
  5. \w等效于[0-9a-zA-Z]————————————w => word
  6. \W等同于[^\w]
  7. \b单词的边界,一边是单词,另一边不是单词

正则表达式用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
match
//匹配IP地址 如:127.234.56.192
Regex.IsMatch(str, "^([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})$");

matches
//找出该字符串中的单词和数字
//June 26 , 1951
string str = "June 26 , 1951 ";
MatchCollection ans = Regex.Matches(str,@"\w+");

foreach(Match match in ans)
{
string a = match.Value;
Console.WriteLine(a);
}

group
//提取每个Email的用户名和域名,使用()提取组

static void Main(string[] args)
{
string path = @"C:\Users\86159\Desktop\co.txt";
/*
mahuateng@qq.com
leibusi@xiaomi.com.cn
biergaici@gmail.com
zhouhongyi@360shit.com
*/
string[] strs = File.ReadAllLines(path);
foreach(string str in strs)
{
//用户名中可以含有数字、大小写字母、_ 、-
Match mc = Regex.Match(str, @"^(?<UserName>[A-Za-z0-9._%+-]+)@(?<yuMing>[A-Za-z0-9.-]+\.[\w]{2,})$");
Console.WriteLine(mc.Groups["UserName"]);//替换索引
Console.WriteLine(mc.Groups["yuMing"]);
}
Console.ReadKey();
}

replace
//替换所匹配的子字符串
static void Main(string[] args)
{
//将连续的 - 都替换成一个 -
//234-----234--------------34------55
string str = "234-----234--------------34------55";

str = Regex.Replace(str, "-+", "-");
Console.WriteLine(str);
//234-234-34-55
Console.ReadKey();
}
//检测违禁字符
static void Main(string[] args)
{
string str = "黑夜总会过去,光明终将到来";
str = Regex.Replace(str, "夜总会", "***");
Console.WriteLine(str);
//黑***过去,光明终将到来
Console.ReadKey();
}

贪婪匹配

1
2
3
4
5
6
7
8
9
10
11
string str = "1111。11。111。111111。";
//贪婪模式:再贪婪一点儿”其后的匹配模式就没法匹配为止
Match mc = Regex.Match(str, @".+。");
Console.WriteLine(mc);
//1111。11。111。111111。

//非贪婪模式:让其后的匹配模式尽早的匹配
Match mc2 = Regex.Match(str, @".+?。");
Console.WriteLine(mc2);
//1111。
Console.ReadKey();

#Day05 2024.05.15

今日知识点:

  1. 并发-并行-同步-异步
  2. 线程方法补充
  3. 线程优先级
  4. 线程生命周期
  5. 多线程访问同一资源问题 (可见性、原子性、有序性)
  6. 死锁
  7. 单例设计模式(多线程不安全
  8. 同步方法
  9. 信号量
  10. 线程池
  11. 异步编程模型(EAP、APM、TPL)吹牛逼用的

今天内容知识前提:主要是CPU部分

并发-并行-同步-异步

  • 并发(Concurrency)

    • 并发是指系统能够同时处理多个任务或多个操作的能力。这些任务可以在时间上重叠,但不一定是同时执行的。
  • 并行(Parallelism)

    • 并行是指系统确实同时执行多个任务或操作。在并行系统中,不同的任务在同一时刻通过不同的处理单元(比如多核处理器或分布式系统中的不同节点)进行处理。
  • 同步(Synchronous)

    • 同步指的是任务按照固定的顺序依次执行,每个任务都要等待上一个任务完成后才能开始执行。任务之间的关系通常是紧密耦合的。
    • 同步通常用于需要严格控制执行顺序和任务之间相互依赖关系的场景,确保数据的一致性和正确性。
  • 异步(Asynchronous)

    • 异步指的是任务不必等待其他任务的完成就可以开始执行。任务之间的执行顺序可以是随机的,并且任务之间的耦合度较低。
    • 异步通常用于需要提高系统的响应性和吞吐量,以及处理可能发生阻塞的操作(比如网络请求、文件IO等),使得系统能够继续执行其他任务而不必等待阻塞操作完成。

线程方法补充

1
2
3
4
5
6
7
8
Thread th = new Thread( () => {
Console.WriteLine("新线程方法补充");
Console.WriteLine("这三个方法是调试使用的,一般程序里最好不要使用");
} );

1、Thread.Sleep(t);使当前线程睡眠t毫秒
2、Thread.Join();使用以后在当前线程执行完之前,其余的线程被阻塞无法执行
3、Thread.Suspend();挂起队列,也就是可以是当前线程暂停。可以使用Thread.Resume()解除挂起状态

线程优先级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static void Main(string[] args)
{
int num = 0;
Thread th1 = new Thread(() =>{
while (true)
{
num++;
}
});
int cnt = 0;
Thread th2 = new Thread(() =>{
while(true)
{
cnt++;
}
});
th1.Start();
th2.Start();

th1.Priority = ThreadPriority.Highest;
th2.Priority = ThreadPriority.Lowest;

Thread.Sleep(100);
Console.WriteLine(num);
Console.WriteLine(cnt);

Console.ReadKey();
}

线程的生命周期


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
static void Main(string[] args)
{
Thread th = new Thread(() =>
{
Console.WriteLine("已经开始执行线程啦");
Thread.Sleep(1000);
for(int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
});
//th.ThreadState == ThreadState.Unstarted 尚未调用UnStarted
//th.ThreadState == ThreadState.Stopped 线程执行结束
//th.ThreadState == ThreadState.Running 线程运行中
//th.ThreadState == ThreadState.WaitSleepJoin 调用Sleep()和Join的时候
//th.ThreadState == ThreadState.Aborted 非正常死亡
Console.WriteLine(th.ThreadState);
th.Start();
Console.WriteLine(th.ThreadState);

while (true)
{
if(th.ThreadState == ThreadState.WaitSleepJoin)
{
Console.WriteLine("线程进入睡眠了");
break;
}
}
}

多线程访问同一资源

  1. 可见性
  2. 原子性
  3. 有序性

volatile解决了可见性和有序性,具体体现在这两方面:

  1. 多线程缓存更新同步volatile 关键字确保了当一个线程更新了 volatile 字段的值后,其他线程立即能够看到这个更新,而不是使用自己线程的缓存中的旧值。
  2. 指令重排序禁止volatile 关键字禁止了编译器和处理器对标记为 volatile 的字段进行指令重排序,这样可以保证程序执行的顺序性,避免了可能的程序错误。

保证原子性则需要使用“锁”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//volatile:解决了可见性和有序性
static volatile int number = 0;
static object o = new object();
static void Main(string[] args)
{
Thread th1 = new Thread(() => {
for (int i = 0; i < 10000; i++)
{
////原子性 加锁
//Monitor.Enter(o);
//number++;
//Monitor.Exit(o);

//lock (o)
//{
// number++;
//}
//便于我们对值类型进行原子操作

Interlocked.Increment(ref number);

//请求cpu,拿走当前线程的执行权,把执行权分配给优先级更高的线程
//如果没有更高优先级的线程,可能会继续执行当前本线程
Thread.Sleep(0);
}
});

Thread th2 = new Thread(() => {
for (int i = 0; i < 10000; i++)
{
//Monitor.Enter(o);
//number++;
//Monitor.Exit(o);
//lock (o)
//{
// number++;
//}
Interlocked.Increment(ref number);

//请求cpu,拿走当前线程的执行权,给【任意】一个线程。
Thread.Sleep(0);
}
});

th1.Start();
th2.Start();

Thread.Sleep(2000);
Console.WriteLine(number);

Console.ReadKey();
}

死锁

造成死锁的四个条件(老生常谈,背就行了)

  1. 互斥条件
  2. 不可抢占条件
  3. 申请和占有条件
  4. 循环等待条件

单例设计模式

  • 这里提单例设计模式是为了说明多线程不安全
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace 单例设计模式
{
internal class Program
{
static void Main(string[] args)
{
for(int i = 0;i < 10;i ++)
{
Thread th = new Thread( () =>
{
SinglePerson sp = SinglePerson.GetSinglePerson();
Thread.Sleep(0);
Console.WriteLine(sp.GetHashCode());
});
th.Start();
}
Console.ReadKey();
}
}

class SinglePerson
{
//构造功函数私有化
private SinglePerson() { }

//private static SinglePerson _singlePerson = null;//懒汉式
private static SinglePerson _singlePerson = new SinglePerson();//饿汉式
private static object o = new object();


public static SinglePerson GetSinglePerson()
{
//lock (o)
//{
// if (_singlePerson == null)
// {
// return _singlePerson = new SinglePerson();
// }
// return _singlePerson;
//}

return _singlePerson;
}

}
}

同步方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace 同步方法
{
internal class Program
{
static int num = 0;
static void Main(string[] args)
{
Thread th = new Thread(AddNumber);
Thread th1 = new Thread(AddNumber);

th.Start();
th1.Start();
Thread.Sleep(1000);

Console.WriteLine(num);
Console.ReadKey ();
}

static void AddNumber()
{
for(int i = 0; i < 10000; i++) {
num++;
Thread.Sleep (0);
}

}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace 同步方法
{
internal class Program
{
static int num = 0;
static void Main(string[] args)
{
Thread th = new Thread(AddNumber);
Thread th1 = new Thread(AddNumber);

th.Start();
th1.Start();
Thread.Sleep(1000);

Console.WriteLine(num);
Console.ReadKey ();
}
[MethodImpl(MethodImplOptions.Synchronized)]//标记为同步方法
static void AddNumber()
{
for(int i = 0; i < 10000; i++) {
num++;
Thread.Sleep (0);
}

}
}
}

信号量

  • 与操作系统中的信号量有区别
  • C#中信号量可以理解成信号灯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
static void Main(string[] args)
{


//Thread th1 = new Thread(() =>
//{
// Console.WriteLine("我是线程一");
//});

//Thread th2 = new Thread(() =>
//{
// Console.WriteLine("我是线程二");
//});

//Thread th3 = new Thread(() =>
//{
// Console.WriteLine("我是线程三");
//});

//th1.Start();
//th2.Start();
//th3.Start();

//ManualResetEvent mre = new ManualResetEvent(false);//false为红灯
AutoResetEvent mre = new AutoResetEvent(false);//“绿灯”过了以后会自动标红灯
//每隔一秒自动让行一辆车
Thread th = new Thread(() =>
{
while(true)
{
Console.WriteLine("前方是红灯,不要执行线程!!!");
Thread.Sleep(1000);
mre.Set();
mre.WaitOne();
Console.WriteLine("看见这条信息就说明变绿灯了");
}
});

th.Start();
Console.WriteLine("前方停止三秒钟");
Thread.Sleep(3000);
//mre.Set();//设置绿灯
//Thread.Sleep(100);
//mre.Reset();//设置红灯

Console.ReadKey();
}

线程池

  • 多线程——->线程池——->三种异步编程——->async和await
  • 线程池的缺点就是无法对目标线程进行操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace 线程池
{
internal class Program
{
static void Main(string[] args)
{
for(int i = 0;i < 10;i ++)
{
Thread th = new Thread(() =>
{
Console.WriteLine("这是我创建的线程,ID是:" + Thread.CurrentThread.ManagedThreadId);
});
th.Start();
}

for(int i = 0;i < 10;i ++)
{
ThreadPool.QueueUserWorkItem((o) =>
{
Console.WriteLine("这是线程池创建的线程,ID是:" + Thread.CurrentThread.ManagedThreadId);
});
}
Console.ReadKey();
}
}
}

事件编程模型(吹牛逼用的)

EAP事件编程(了解)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
static void Main(string[] args)
{
WebClient wc = new WebClient();

//string str = wc.DownloadString("http://www.baidu.com");

//Console.WriteLine(str);

//下载完成之后的事件
wc.DownloadStringCompleted += Wc_DownloadStringCompleted;

wc.DownloadStringAsync(new Uri("http://www.svipclass.com"));

for (int i = 0; i < 20; i++)
{
Console.WriteLine("Hello World");
}

Console.ReadKey();
Console.ReadKey();
}

private static void Wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
Console.WriteLine(e.Result);
}

APM事件编程(了解)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
string path = @"C:\Users\ThinkPad\Desktop\餐饮项目开发步骤.txt";
//AMP
//1、BeginXXXX开始
//2、维护一个异步方法的返回值
//3、EndXXXXX结束
using (FileStream fsRead = new FileStream(path, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[1024 * 1024];

IAsyncResult asyncResult = fsRead.BeginRead(buffer, 0, buffer.Length, null, null);
//asyncResult 维护着信号量对象
asyncResult.AsyncWaitHandle.WaitOne();

int r = fsRead.EndRead(asyncResult);

string str = Encoding.UTF8.GetString(buffer, 0, r);
Console.WriteLine(str);
}

Console.ReadKey();

TPL事件编程(最简单的await和async)一定带掌握

  1. 异步方法的返回值必须是Task的泛型。int–Task void — Task
  2. 异步方法必须被标记为async
  3. 异步方法有传染性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static async Task Main(string[] args)
{
int length = await GetDownloadStr("https://www.baidu.com", @"C:\Users\86159\Desktop\cxxxx.txt");
//int length = 0;
Console.WriteLine(length);
Console.ReadKey();
}

static async Task<int> GetDownloadStr(string url, string path)
{
WebClient wc = new WebClient();

string s = await wc.DownloadStringTaskAsync(url);

//Task<string> s = wc.DownloadStringTaskAsync(url);
//await s;

Console.WriteLine(s);

using (FileStream fsWrite = new FileStream(path, FileMode.Create, FileAccess.Write))
{
byte[] buffer = Encoding.UTF8.GetBytes(s);

await fsWrite.WriteAsync(buffer, 0, buffer.Length);
}

return s.Length;
}

#Day06-07 2024.05.16-2024.05.17

设计原则(面向抽象编程)

写类的设计第一件事就是封装变化。

-降低耦合度

继承的问题(以后尽量不要使用继承)

-1、破坏了系统的封装性,基类发生了改变,子类的实现也会发生改变,子类的实现也会发生改变。
-2、子类如果不需要父类的某一方法,则系统耦合度变高。
-3、继承是静态的,不能在程序运行时发生改变

类与类之间的关系

-泛化、实现、组合、聚合、关联、依赖

1、单一职责原则(SRP)

  • 首先也是最重要的,想要实现高内聚低耦合必须遵守的原则。

条例

  1. 应该有且只有一个引起类变更的原因(一个类只负责一件事儿)

好处

  1. 提高代码的可读性,提高系统的可维护性
  2. 降低类的复杂性,一个模块只负责一个人职责,提高系统的可拓展性和可维护性
  3. 降低变更引起的风险,变更时必然的,如果单一职责做得好,当修改一个功能的时候可以显著的降低对另一个功能的影响。

2、开放封闭原则(OCP)

  • 开放封闭原则是是面向对象设计的终极目标,而依赖倒置原则是实现开放封闭原则的的基础
  • 如果开放封闭原则是设计大楼的蓝图,那么依赖倒置原则就是大楼的钢铁架构

条例

  1. 开放封闭原则是面向对象所有原则的核心。
    • 对功能拓展开放
    • 面向修改代码封闭
  2. 需求改变时,在不改变实体源代码接(类、接口、方法等)的前提下,通过拓展功能,使其满足新的需求。

3、依赖倒置原则(DIP)

条例

  1. 高层模块不应该依赖于底层模块,两个都应该依赖于抽象
  2. 抽象不应该依赖于细节,细节应该依赖于抽象
  3. 依赖倒置原则的本质就是通过抽象(接口或抽象类)是各个类和模块的实现彼此独立,互不影响,实现模块间的松耦合

4、里式替换原则(LSP)

条例

  1. 如果S是T的子类型,则T类型的对象可以替换为S类型的对象
  2. 所有引用父类对象的地方,都可以使用其子类型代替
  3. 子类可以替代父类

5、接口分离原则(ISP)

条例

  1. 客户端不应该依赖它不需要的接口
  2. 一个类对另一个类的依赖应该建立在最小接口上
  3. 接口尽量细分,不要在一个接口中放很多种方法

6、合成复用原则(CRP)

条例

  1. 又称组合/聚合复用原则
  2. 尽量使用对象组合,而不是继承达到复用
  3. 如何实现?

7、迪米特原则(TLKP/DP)

  • 和直接朋友通信
    1. 成员对象(属性、字段)
    2. 方法参数
    3. 方法返回值

条例

  1. 它要求一个对象应该对其他对象有最少的了解
  2. 降低类之间的耦合
  3. 迪米特原则实际上就是一个类在创建方法和属性时要遵守的法则

设计原则总结

#Day08 - 09 2024.05.18 - 25

说一下你对深拷贝和浅拷贝的理解

1、单例设计模式

2、简单工厂设计模式

  • 简单工厂:一个工厂类,一个产品抽象类,工厂类创建方法传入参数并判断,选择创建具体的产品对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
internal class Program
{
static void Main(string[] args)
{
//根据用户的不同需求,创建不同的对象
//提供了一个静态的方法,接收用户的输入,返回不同的对象(父类)
//加减乘除
//抽象的产品父类----->具体的产品子类
//工厂:提供了一个静态的方法,接收用户的输入,返回不同的对象(父类)

//简单工厂:一个工厂类,一个产品抽象类,工厂类创建方法传入参数并判断,选择创建具体的产品对象
Console.WriteLine("请输入运算符");
string oper = Console.ReadLine();
Console.WriteLine("请输入你要计算的第一个数字");
int n1 = int.Parse(Console.ReadLine());
Console.WriteLine("请输入你要计算的第二个数字");
int n2 = int.Parse(Console.ReadLine());
Factory CRF = new Factory(oper,n1,n2);
CRF.GetResult();
Console.ReadKey();
}
}

class Factory
{
public String oper { get; set; }
public int n1 { get; set; }
public int n2 { get; set; }
public Factory(String oper, int n1, int n2)
{
this.oper = oper;
this.n1 = n1;
this.n2 = n2;
}
public void GetResult()
{
if (oper == "+")
{
Calculator cal = new Add(n1,n2);
Console.WriteLine(cal.GetResult());
}
else if (oper == "-")
{
Calculator cal = new Sub(n1, n2);
Console.WriteLine(cal.GetResult());
}
else if(oper == "*")
{
Calculator cal = new Mul(n1, n2);
Console.WriteLine(cal.GetResult());
}
else if(oper == "/")
{
Calculator cal = new Div(n1, n2);
Console.WriteLine(cal.GetResult());
}
}
}


abstract class Calculator
{
////public string Oper { get; set; }
//public int n1 { get; set; }
//public int n2 { get; set; }//这里是有问题的,n1,n2没有传参
////public Calculator(string oper) { this.Oper = oper; }
//public abstract double GetResult(int n1,int n2);

public int n1 { get; set; }
public int n2 { get; set; }

public Calculator(int n,int m)
{
this.n1 = n;
this.n2 = m;
}

public abstract double GetResult();
}

class Add : Calculator
{
public Add(int n, int m) : base(n, m)
{
}

public override double GetResult()
{
return this.n1 + this.n2;
}
}

class Sub : Calculator
{
public Sub(int n, int m) : base(n, m)
{
}

public override double GetResult()
{
return this.n1 - this.n2;
}
}

class Mul : Calculator
{
public Mul(int n, int m) : base(n, m)
{
}

public override double GetResult()
{
return this.n1 * this.n2;
}
}

class Div : Calculator
{
public Div(int n, int m) : base(n, m)
{
}

public override double GetResult()
{
return this.n1 / this.n2;
}
}

3、工厂设计模式

  • 工厂设计模式:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量的if-else判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
internal class Program
{
static void Main(string[] args)
{
//工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量的if-else判断
//AbstractFactory factory = new AddFactory();
//Console.WriteLine(factory.GetExatCalculator(10, 20).GetResult());
double result = GetResult(new AddFactory(), 10, 20);
Console.WriteLine(result);
Console.ReadKey();
}

static double GetResult(AbstractFactory af,int n1,int n2)
{
AbstractFactory factory = af;
return af.GetExatCalculator(n1,n2).GetResult();
}
}

abstract class AbstractFactory
{
/// <summary>
/// 抽象的产品工厂,负责创建所有的子类产品,所以要返回抽象的产品父类
/// </summary>
/// <param name="n1"></param>
/// <param name="n2"></param>
/// <returns></returns>
public abstract Calculator GetExatCalculator(int n1,int n2);
}

class AddFactory : AbstractFactory
{
public override Calculator GetExatCalculator(int n1, int n2)
{
return new Add(n1,n2);
}
}

class SubFactory : AbstractFactory
{
public override Calculator GetExatCalculator(int n1, int n2)
{
return new Sub(n1, n2);
}
}

class MulFactory : AbstractFactory
{
public override Calculator GetExatCalculator(int n1, int n2)
{
return new Mul(n1, n2);
}
}

class DivFactory : AbstractFactory
{
public override Calculator GetExatCalculator(int n1, int n2)
{
return new Div(n1, n2);
}
}

abstract class Calculator
{
public double n1 { get; set; }
public double n2 { get; set; }
public Calculator(double n1, double n2)
{
this.n1 = n1;
this.n2 = n2;
}
public abstract double GetResult();
}

class Add : Calculator
{
public Add(int n, int m) : base(n, m)
{
}

public override double GetResult()
{
return this.n1 + this.n2;
}
}

class Sub : Calculator
{
public Sub(int n, int m) : base(n, m)
{
}

public override double GetResult()
{
return this.n1 - this.n2;
}
}

class Mul : Calculator
{
public Mul(int n, int m) : base(n, m)
{
}

public override double GetResult()
{
return this.n1 * this.n2;
}
}

class Div : Calculator
{
public Div(int n, int m) : base(n, m)
{
}

public override double GetResult()
{
return this.n1 / this.n2;
}
}

4、抽象工厂设计模式(难)

  • 抽象工厂设计模式:多个工厂类,多个产品抽象类,产品子类分组,同一工厂实现类创建同组中的不同产品,减少了工厂子类的数量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
internal class Program
{
static void Main(string[] args)
{
//多个工厂类,多个产品抽象类,产品子类分组,同一工厂实现类创建同组中的不同产品,减少了工厂子类的数量
IAbstractFactory factory = new DellFactory();
IScreen screen = factory.GetScreenBrand();
screen.GetBrand();
IKeyBoard keyBoard = factory.GetKeyBoardBrand();
keyBoard.GetBrand();
IMouse mouse = factory.GetMouseBrand();
mouse.GetBrand();
Console.ReadKey();
}
}

interface IKeyBoard
{
void GetBrand();
}
class DellKeyBoard : IKeyBoard
{
public void GetBrand()
{
Console.WriteLine("我是Dell键盘");
}
}
class HPKeyBoard : IKeyBoard
{
public void GetBrand()
{
Console.WriteLine("我是HP键盘");
}
}

interface IMouse
{
void GetBrand();
}
class DellMouse : IMouse
{
public void GetBrand()
{
Console.WriteLine("我是Dell鼠标");
}
}
class HPMouse : IMouse
{
public void GetBrand()
{
Console.WriteLine("我是HP鼠标");
}
}

interface IScreen
{
void GetBrand();
}
class DellScreen : IScreen
{
public void GetBrand()
{
Console.WriteLine("我是Dell屏幕");
}
}
class HPScreen : IScreen
{
public void GetBrand()
{
Console.WriteLine("我是HP屏幕");
}
}

interface IAbstractFactory
{
IMouse GetMouseBrand();
IKeyBoard GetKeyBoardBrand();
IScreen GetScreenBrand();
}

class DellFactory : IAbstractFactory
{

public IKeyBoard GetKeyBoardBrand()
{
return new DellKeyBoard();
}

public IMouse GetMouseBrand()
{
return new DellMouse();
}

public IScreen GetScreenBrand()
{
return new DellScreen();
}
}

class HPFactory : IAbstractFactory
{
public IKeyBoard GetKeyBoardBrand()
{
return new HPKeyBoard();
}

public IMouse GetMouseBrand()
{
return new HPMouse();
}

public IScreen GetScreenBrand()
{
return new HPScreen();
}
}

5、原型设计模式

  • 完成浅拷贝和深拷贝的理解和使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace 原型设计模式
{
internal class Program
{
static void Main(string[] args)
{
//深拷贝和浅拷贝
//浅拷贝有现成方法:MemberWiseClone
//深拷贝只有序列化这一条路,不过不同于配置文件的序列化,深拷贝的序列化是拷贝放在内存里的
//序列化记得要贴狗皮膏药[serializable]


Person p = new Person();
p.Name = "周杰伦"; //0x02AD2340
p.Age = 44; //0x0000002C
p.Dog = new Dog { Name = "旺财" }; //0x02AD2390
//浅拷贝
//Person p1 = new Person();
//p1.Name = p.Name; //0x02AD2340
//p1.Age = p.Age; //0x0000002C
//p1.Dog = p.Dog; //0x02AD2390

//或者

Person p1 = p.PeronsWiseCopy();
p1.Name = p.Name; //0x02DA2340
p1.Age = p.Age; //0x0000002C
p1.Dog = p.Dog; //0x031A237C
//深拷贝:利用序列化

Person p2 = p.PersonDeepCopy(p);
string name = p2.Name;//0x02AD8DE4
int age = p2.Age;
Dog dog = p2.Dog;//0x02AD95E0


Console.WriteLine("Ok");
Console.ReadKey ();
}
}
[Serializable]
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Dog Dog { get; set; }

//在类中,提供一个方法,用于对对象的实现深浅拷贝
//浅拷贝
public Person PeronsWiseCopy()
{
return (Person)this.MemberwiseClone();
}

//深拷贝
public Person PersonDeepCopy(Person p)
{
using(MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, p);

ms.Position = 0;

return (Person)bf.Deserialize(ms);
}
}

}
[Serializable]
class Dog
{
public string Name { get; set; }
}
}

6、建造者设计模式(难)

  • 创建多子类部件的对象
    1. 完整的对象,需要多个子部件对象?
    2. 完整的对象,需要几个顺序进行子部件对象的创建?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 建造者设计模式
{
internal class Program
{
static void Main(string[] args)
{
//确定要创建好电脑对象
AbstractBuilder builder = new GoodComoputer();
//组装
Director dir = new Director(builder);
//组装完成后返回
Computer cpu = builder.GetComputer();
cpu.ShowComponent();
Console.ReadKey();
}
}
/// <summary>
/// 职责:加入部件和展示部件
/// </summary>
class Computer
{
List<string> parts = new List<string>();

public void SetComponent(string s)
{
parts.Add(s);
}
public void ShowComponent()
{
foreach (string s in parts)
{
Console.WriteLine(s);
}
}

}
/// <summary>
/// 抽象的建造者
/// </summary>
interface AbstractBuilder
{
/// <summary>
/// 构建计算机对象各个组件的抽象方法
/// </summary>
void SetCPU();
void SetMemory();
void SetDisk();
void SetPower();

/// <summary>
/// 返回构建完成的对象
/// </summary>
/// <returns></returns>
Computer GetComputer();
}
/// <summary>
/// 应该是先具体后抽象
/// 知道这个具体该做什么以后再抽象成接口或抽象类
/// </summary>
class BadComoputer : AbstractBuilder
{
private Computer computer = new Computer();
public Computer GetComputer()
{
return computer;
}

public void SetCPU()
{
computer.SetComponent("I1的CPU");
}

public void SetDisk()
{
computer.SetComponent("1Kb的硬盘");
}

public void SetMemory()
{
computer.SetComponent("1Mb的内存");
}

public void SetPower()
{
computer.SetComponent("1W的电源");
}
}

class GoodComoputer : AbstractBuilder
{
private Computer computer = new Computer();
public Computer GetComputer()
{
return computer;
}

public void SetCPU()
{
computer.SetComponent("I700的CPU");
}

public void SetDisk()
{
computer.SetComponent("100Pb的硬盘");
}

public void SetMemory()
{
computer.SetComponent("1000G的内存");
}

public void SetPower()
{
computer.SetComponent("1000W的电源");
}
}
/// <summary>
/// 部件的构建顺序由导演类掌控
/// </summary>
class Director
{
public Director(AbstractBuilder ab)
{
ab.SetCPU();
ab.SetDisk();
ab.SetMemory();
ab.SetPower();
}
}
}

7、适配器设计模式

  • 创建一个新类使用老方法实现新接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
internal class Program
{
static void Main(string[] args)
{
ChargeAdapter adapter = new ChargeAdapter();
adapter.IPhoneCharge();
Console.ReadKey();
}
}

/// <summary>
/// 原有的,在老环境下能正常使用的对象
/// 安卓充电线
/// </summary>
class AndroidAdaptee
{
public void AndroidCharge()
{
Console.WriteLine("使用安卓充电器充电");
}
}

/// <summary>
/// 目标接口
/// </summary>
interface IphoneTarget
{
void IPhoneCharge();
}

/// <summary>
/// 适配器对象,实现目标接口,并且维护一个原有的对象
/// </summary>
class ChargeAdapter : IphoneTarget
{
//安卓充电器对象
private AndroidAdaptee adaptee = new AndroidAdaptee();
//实现苹果手机充电的接口方法
public void IPhoneCharge()
{
adaptee.AndroidCharge();
}
}

8、装饰器设计模式(难)

  • 不明白为什么要设计成对象套对象?
  • 明白一点但没法说出来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
internal class Program
{
static void Main(string[] args)
{
Bervage bervage = new MilkTea();
Decorater buding1 = new Buding(bervage);
Decorater boba = new Boba(buding1);
Decorater xiancao = new Xiancao(boba);
Console.WriteLine(xiancao.GetMoney());
Console.ReadKey();
}
}
/// <summary>
/// 饮料,一切的父类
/// </summary>
abstract class Bervage
{
public abstract double GetMoney();
}

class MilkTea : Bervage
{
public override double GetMoney()
{
Console.WriteLine("奶茶10一杯");
return 10;
}
}

class FruitTea : Bervage
{
public override double GetMoney()
{
Console.WriteLine("果茶12一杯");
return 12;
}
}

class Soda : Bervage
{
public override double GetMoney()
{
Console.WriteLine("苏打水8元一杯");
return 8;
}
}

abstract class Decorater : Bervage
{
//维护一个父类的引用
//加小料得先有饮料,因此得注入
protected Bervage bervage;

public Decorater(Bervage bervage)
{
this.bervage = bervage;
}
/// <summary>
/// 返回总价格
/// </summary>
/// <returns></returns>
public override double GetMoney()
{
return this.bervage.GetMoney();
}
}

class Buding : Decorater
{
private static double money = 3;
public Buding(Bervage bervage) : base(bervage)
{
}

public override double GetMoney()
{
return base.GetMoney() + money;
}
}

class Boba : Decorater
{
private static double money = 3.5;
public Boba(Bervage bervage) : base(bervage)
{
}

public override double GetMoney()
{
return base.GetMoney() + money;
}
}

class Xiancao : Decorater
{
private static double money = 4;
public Xiancao (Bervage bervage) : base(bervage)
{
}

public override double GetMoney()
{
return base.GetMoney() + money;
}
}

9、代理设计模式

  • 代理进行某些行为,有些需要权限,有些不需要(clash)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
internal class Program
{
static void Main(string[] args)
{
ISubject subject = new Proxy(new RealSubject());
ClassFlower cf = new ClassFlower();
cf.Name = "如花";
subject.GiveSmoking(cf);
subject.GiveBeer(cf);
subject.DJ(cf);
Console.ReadKey();
}
}

class ClassFlower
{
public string Name { get; set; }
}

/// <summary>
/// 代理接口,定义了实体和代理共有的成员
/// </summary>
interface ISubject
{
void GiveSmoking(ClassFlower cf);
void GiveBeer(ClassFlower cf);
void DJ(ClassFlower cf);
}

class RealSubject : ISubject
{
public void DJ(ClassFlower cf)
{
Console.WriteLine("老王请"+cf.Name +"去蹦迪");
}

public void GiveBeer(ClassFlower cf)
{
Console.WriteLine("老王请"+cf.Name +"喝台子");
}

public void GiveSmoking(ClassFlower cf)
{
Console.WriteLine("老王请"+cf.Name+"抽华子");
}
}

/// <summary>
/// 代理类
/// </summary>
class Proxy : ISubject
{
//代理需要维护一个RealSubject的引用
private RealSubject _realSubject;

public Proxy(RealSubject realSubject)
{
this._realSubject = realSubject;
}
public void DJ(ClassFlower cf)
{
this._realSubject.DJ(cf);
}

public void GiveBeer(ClassFlower cf)
{
this._realSubject.GiveBeer(cf);
}

public void GiveSmoking(ClassFlower cf)
{
this._realSubject.GiveSmoking(cf);
}
}

10、外观设计模式

  • 我理解的就是极致封装,只留给使用者一个接口(将外观设计地好看)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
internal class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.PToZM();
Console.ReadKey();
}
}

class Person
{
ZWDT zwdt = new ZWDT();
public void PToZM()
{
zwdt.ZM();
}
}

class ZWDT
{
public void WalkToPolice()
{
Console.WriteLine("去派出所班出生证明");
}

public void WalkToStreet()
{
Console.WriteLine("去街道开具户籍证明");
}
public void WalkToShopital()
{
Console.WriteLine("去医院开出生证明");
}
public void ZM()
{
WalkToPolice();
WalkToStreet();
WalkToShopital();
}
}

11、桥接设计模式

  • 组合复用原则

12、组合设计模式

  • 类似于Winform中的TreeView组件(如图所示)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _01_组合设计模式
{
internal class Program
{
static void Main(string[] args)
{
//创建公司节点(根节点)
Component component = new Coposite() { Name = "华北理工大学" };
//创建树枝节点
Component composite = new Coposite() { Name = "计算机软件与应用专业1班" };
//创建叶子节点
Leaf leaf1 = new Leaf() { Name = "瑶瑶" };
Leaf leaf2 = new Leaf() { Name = "张峥" };
//把树枝节点,添加到根节点
component.Add(composite);
//把叶子节点,添加到树枝节点
composite.Add(leaf1);
composite.Add(leaf2);
//打印树桩对象图
component.Display(4);
Console.ReadKey();



}
}
/// <summary>
/// 根节点,定义树枝节点和叶子节点,共有的属性和方法
/// </summary>
abstract class Component
{
/// <summary>
/// 定义节点的名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 添加节点
/// </summary>
/// <param name="component"></param>
public abstract void Add(Component component);
/// <summary>
/// 删除节点
/// </summary>
/// <param name="component"></param>
public abstract void Remove(Component component);
/// <summary>
/// 展示节点
/// </summary>
public abstract void Display(int depth);
}


/// <summary>
/// 树枝节点,下面可以添加树叶
/// </summary>
class Coposite : Component
{
//维护树枝节点和树叶节点
private List<Component> listComps = new List<Component>();

/// <summary>
/// 添加子节点
/// </summary>
/// <param name="component"></param>
public override void Add(Component component)
{
listComps.Add(component);
}

public override void Display(int depth)
{
Console.WriteLine(new string('-', depth) + this.Name);
//打印树叶的名字
foreach (var item in listComps)
{
//递归
item.Display(depth+4);
}
}

public override void Remove(Component component)
{
listComps.Remove(component);
}
}

/// <summary>
/// 树叶节点
/// </summary>
class Leaf : Component
{
public override void Add(Component component)
{

}

public override void Display(int depth)
{
Console.WriteLine(new string('-', depth) + this.Name);
}

public override void Remove(Component component)
{

}
}
}

13、享元设计模式

  • 目的就是节省资源(共享单车)

  • 享元设计模式一定得有一个享元工厂,用来管理FlyWeight对象。它主要用来确保合理的使用Flyweight,当用户请求一个FlyWeight时,FlyWeightFactory对象提供一个已创建的实例过着创建一个。

  •   using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      
      namespace _04_享元设计模式
      {
          internal class Program
          {
              static void Main(string[] args)
              {
                  //1、创建享元工厂
                  Factory factory = new Factory();
                  FlyWeight flyWeight = factory.GetBike();
                  flyWeight.Ride("张三");
                  FlyWeight flyWeight2 = factory.GetBike();
                  flyWeight2.Ride("李四");
      
                  flyWeight2.Back("李四");
      
                  FlyWeight flyWeight3 = factory.GetBike();
                  flyWeight3.Ride("王五");
      
                  //FlyWeight flyWeight4 = factory.GetBike();
                  //flyWeight4.Ride("赵六");
      
                  //FlyWeight flyWeight5 = factory.GetBike();
                  //flyWeight5.Ride("田七");
                  Console.ReadKey();
      
              }
          }
      
          /// <summary>
          /// 共享单车的父类    小黄车  小蓝车  
          /// </summary>
          abstract class FlyWeight
          {
              //外部状态  state----> 0 停止状态(归还了),可以随时被使用    1--骑行状态(使用了)
              public int State { get; set; } //0 - 1  骑行或者归还的状态  外部状态
      
              public int ID { get; set; } //二维码  内部状态
              public abstract void Back(string user);//归还了
      
              public abstract void Ride(string user);//骑走了
      
          }
      
          /// <summary>
          /// 小黄车
          /// </summary>
          class LittlYellowBike : FlyWeight
          {
              public override void Back(string user)
              {
                  Console.WriteLine("用户" + user + "归还了ID是" + this.ID + "的小黄车");
                  this.State = 0;
              }
                  
              public override void Ride(string user)
              {
                  Console.WriteLine("用户" + user + "骑走了ID是" + this.ID + "的小黄车");
                  this.State = 1;
              }
          }
      
          class Factory
          {
              //维护所有的小黄车对象
              List<FlyWeight> listBikes = new List<FlyWeight>();
      
              /// <summary>
              /// 创建小黄车的初始对象
              /// </summary>
              public Factory()
              {
                  for (int i = 0; i < 3; i++)
                  {
                      listBikes.Add(new LittlYellowBike() { ID = i + 1 });
                  }
              }
              public FlyWeight GetBike()
              {
                  for (int i = 0; i < listBikes.Count; i++)
                  {
                      //判断state的状态
                      if (listBikes[i].State == 0)
                      {
                          return listBikes[i];
                      }
                  }
      
                  //循环没执行,说明没有可用的自行车,创建一个新的
                  LittlYellowBike littlYellowBike = new LittlYellowBike() { ID = listBikes.Count+1};
                  listBikes.Add(littlYellowBike);
                  //拿最后一辆车
                  return listBikes[listBikes.Count - 1];
              }
          }
      
      
      }
      
      
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119



    ## 14、中介者设计模式



    ## 15、发布-订阅模式(观察者设计模式)

    - 常用于UP主发布视频是向粉丝推送或者UP主向粉丝推送信息

    ```C#

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace 解耦训练
    {
    internal class Program
    {
    static void Main(string[] args)
    {
    //UP主
    HappyNewYear happyNewYear = new HappyNewYear() { Information = "三里屯蹦迪" };
    //粉丝
    Student s1 = new Student() { Name = "张三"};
    Student s2 = new Student() { Name = "李四" };
    Student s3 = new Student() { Name = "王五" };
    Student s4 = new Student() { Name = "赵六" };

    //让粉丝开始关注主播
    happyNewYear.Attach(s1);
    happyNewYear.Attach(s2);
    happyNewYear.Attach(s3);
    happyNewYear.Attach(s4);

    happyNewYear.Notify();
    Console.ReadKey();

    }
    }




    /// <summary>
    /// UP主的父类
    /// </summary>
    public interface ISubject
    {
    void Attach(IObserver observer);
    void Notify();
    }

    /// <summary>
    /// UP主
    /// </summary>
    public class HappyNewYear : ISubject
    {
    /// <summary>
    /// 要通知给粉丝的消息
    /// </summary>
    public string Information { get; set; }

    // 维护所有的粉丝
    private List<IObserver> observers = new List<IObserver>();

    /// <summary>
    /// 添加粉丝
    /// </summary>
    /// <param name="observer"></param>
    public void Attach(IObserver observer)
    {
    observers.Add(observer);
    }

    /// <summary>
    /// 通知所有的粉丝,关于HappyNewYear的活动信息
    /// </summary>
    public void Notify()
    {
    foreach (var observer in observers)
    {
    // 每一个粉丝,都能收到消息
    observer.Update(Information);
    }
    }
    }

    /// <summary>
    /// 粉丝的父类
    /// </summary>
    public interface IObserver
    {
    void Update(string message);
    }

    /// <summary>
    /// 粉丝
    /// </summary>
    public class Student : IObserver
    {
    public string Name { get; set; }

    /// <summary>
    /// 粉丝收到Up主的消息
    /// </summary>
    /// <param name="message">收到的消息</param>
    public void Update(string message)
    {
    // 收Up主的消息
    Console.WriteLine("{0}收到了2024年12月31号去{1}消息", this.Name, message);
    }
    }
    }

16、迭代器设计模式

  • 我目前只了解,不会写

17、访问者设计模式

  • 懂了,还不熟
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _08_访问者设计模式
{
internal class Program
{
static void Main(string[] args)
{
//1、创建访问者对象
Visitors visitorsHR = new HR();
Visitors visitorsCW = new CaiWu();

//2、创建被访问者对象
FullTimeWorker fullTimeWorker1 = new FullTimeWorker("全职张三",180,5000);
FullTimeWorker fullTimeWorker2 = new FullTimeWorker("全职李四", 140, 5000);
FullTimeWorker fullTimeWorker3 = new FullTimeWorker("全职王五", 120, 5000);

PartTimeWorker partTimeWorker1 = new PartTimeWorker("兼职赵六", 200, 5000);
PartTimeWorker partTimeWorker2 = new PartTimeWorker("兼职赵六", 200, 5000);
PartTimeWorker partTimeWorker3 = new PartTimeWorker("兼职赵六", 200, 5000);

//3、创建objectStructure对象
ObjectStucture os = new ObjectStucture();
os.AddElements(fullTimeWorker1);
os.AddElements(fullTimeWorker2);
os.AddElements(fullTimeWorker3);
os.AddElements(partTimeWorker1);
os.AddElements(partTimeWorker2);
os.AddElements(partTimeWorker3);

//4、访问者,开始访问被访问者
os.VisitElements(visitorsHR);
Console.ReadKey();

}
}

/// <summary>
/// 抽象的访问者
/// </summary>
abstract class Visitors
{
public abstract void Visit(FullTimeWorker fullTimeWorker);
public abstract void Visit(PartTimeWorker partTimeWorker);


}

/// <summary>
/// 具体的访问者1
/// </summary>
class HR : Visitors
{
public override void Visit(FullTimeWorker fullTimeWorker)
{
double hours = fullTimeWorker.WorkHours;
string name = fullTimeWorker.Name;
if (hours > 160)
{
Console.WriteLine("人事部建议给{0}加薪", name);
}
else
{
Console.WriteLine("人事部建议干掉{0}",name);
}
}

public override void Visit(PartTimeWorker partTimeWorker)
{
double hours = partTimeWorker.WorkHours;
string name = partTimeWorker.Name;

if (hours > 160)
{
Console.WriteLine("人事部建议给{0}友好的劝退", name);
}
else
{
Console.WriteLine("赶紧让{0}滚犊子",name);
}

}
}

/// <summary>
/// 具体的访问者2 ,财务部算工资
/// </summary>
class CaiWu : Visitors
{
public override void Visit(FullTimeWorker fullTimeWorker)
{
//40⼩时/>40⼩时/100/⼩时/<40⼩时/80/⼩时
double hours = fullTimeWorker.WorkHours;
double salary = fullTimeWorker.Salary;
string name = fullTimeWorker.Name;

if (hours >= 160)
{
//加班了
Console.WriteLine("{0}本月应出勤160小时,实际出勤{1}小时,合计加班{2}小时,总薪资为{3}",
name, hours, hours - 160, hours * 100);
}
else
{
Console.WriteLine("{0}本月应出勤160小时,实际出勤{1}小时,合计旷工{2}小时,总薪资为{3}",
name, hours, 160 - hours, hours * 80);
}
}

public override void Visit(PartTimeWorker partTimeWorker)
{
//按实际出勤时间核算⼯资
double hours = partTimeWorker.WorkHours;
double salary = partTimeWorker.Salary;
string name = partTimeWorker.Name;
Console.WriteLine("{0}本月出勤{1}小时,合计薪资为{2}", name, hours, hours * 20);
}
}

/// <summary>
/// 抽象的被访问者
/// </summary>
abstract class Element
{
public string Name { get; set; }
public int WorkHours { get; set; }
public double Salary { get; set; }
public Element(string name, int workHours, double salary)
{
this.Name = name;
this.WorkHours = workHours;
this.Salary = salary;
}

public abstract void Accept(Visitors visitors);

}

/// <summary>
/// 具体的被访问者1
/// </summary>
class FullTimeWorker : Element
{

public FullTimeWorker(string name, int hours, double salary) : base(name, hours, salary)
{

}
/// <summary>
/// 接收访问者的访问
/// </summary>
/// <param name="visitors"></param>
public override void Accept(Visitors visitors)
{
visitors.Visit(this);
}


}

/// <summary>
/// 具体的被访者2
/// </summary>
class PartTimeWorker : Element
{

public PartTimeWorker(string name, int hours, double salary) : base(name, hours, salary)
{

}
public override void Accept(Visitors visitors)
{
visitors.Visit(this);
}
}


/// <summary>
/// 让客户端少承担一些职责
/// </summary>
class ObjectStucture
{
//存储被访问者
private List<Element> list = new List<Element>();

/// <summary>
/// 添加被访问者
/// </summary>
/// <param name="element"></param>
public void AddElements(Element element)
{
list.Add(element);
}
/// <summary>
/// 访问被访问者
/// </summary>
public void VisitElements(Visitors visitors)
{
foreach (var item in list)
{
item.Accept(visitors);
}
}
}
}

18、责任链设计模式

19、模板设计模式

20、策略设计模式

21、命令设计模式

22、备忘录设计模式

23、状态设计模式

24、解释器设计模式