大话设计模式 - 读书笔记

简单工厂模式

简单工厂示例:算数运算实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//运算工厂
public class OperationFactory{
public static Operation createOperate(string operate){
Operation oper = null;
switch (operate){
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//运算符类
public class Operation{
private double _numberA = 0;
private double _numberB = 0;

public double NumberA{
get { return _numberA; }
set { _numberA = value; }
}
public double NumberB{
get { return _numberB; }
set { _numberB = value; }
}
//虚方法,用于子类定义自己的实现
public virtual double GetResult(){
double result = 0;
return result;
}
}
1
2
3
4
5
6
7
8
//加法类
public class OperationAdd : Operation{
public override double GetResult(){
double result = 0;
result = NumberA + NumberB;
return result;
}
}
1
2
3
4
5
6
7
8
//减法类
public class OperationSub : Operation{
public override double GetResult(){
double result = 0;
result = NumberA - NumberB;
return result;
}
}
1
2
3
4
5
6
7
8
//乘法类
public class OperationMul : Operation{
public override double GetResult(){
double result = 0;
result = NumberA * NumberB;
return result;
}
}
1
2
3
4
5
6
7
8
9
10
11
//除法类
public class OperationDiv : Operation{
public override double GetResult(){
double result = 0;
if(NumberB == 0){
throw new Exception("除数不能为0");
}
result = NumberA / NumberB;
return result;
}
}
1
2
3
4
5
6
//调用代码
Operation oper;
oper = OperationFactory.createOperate("+");
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();

策略模式

策略模式就是用来封装算法的,但是在实践中,它几乎可以用来封装任何类型的规则,只要在分析过程中知道需要在不同时间应用不同的业务规则,就可以考虑使用策略模式
策略模式将不同的算法封装成一个对象,这些不同的算法从一个抽象类或者一个接口中派生出来,客户端持有一个抽象的策略的引用,这样客户端就能动态的切换不同的策略
它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的方法,减少了对各种算法类与使用算法类之间的耦合
策略模式的Strategy类层次为Context定义了一系列的可供重用的算法或行为,继承有助于析取出这些算法中的公共功能
策略模式的另一个优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试

策略模式示例

1
2
3
4
5
//抽象算法类
abstract class Strategy{
//算法方法
public abstract void AlgorithmInterface();
}
1
2
3
4
5
6
7
//具体算法A
class ConcreteStrategyA : Strategy{
//算法A的具体实现
public override void AlgorithmInterface(){
//具体实现
}
}
1
2
3
4
5
6
7
//具体算法B
class ConcreteStrategyB : Strategy{
//算法B的具体实现
public override void AlgorithmInterface(){
//具体实现
}
}
1
2
3
4
5
6
7
//具体算法C
class ConcreteStrategyC : Strategy{
//算法C的具体实现
public override void AlgorithmInterface(){
//具体实现
}
}
1
2
3
4
5
6
7
8
9
10
11
///上下文 用一个ConcreteStrategy来维护,维护一个对Strategy对象的引用
class Context{
Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
//上下文接口
public void ContextInterface(){
strategy.AlgorithmInterface();
}
}
1
2
3
4
5
6
7
8
9
10
//客户端代码
Context context;
context = new Context(new ConcreteStrategyA());
context.ContextInterface();

context = new Context(new ConcreteStrategyB());
context.ContextInterface();

context = new Context(new ConcreteStrategyC());
context.ContextInterface();

策略模式结合简单工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Context{
Strategy strategy;
public Context(string type){
switch (type){
case "typeA":
ConcreteStrategyA csA = new ConcreteStrategyA();
strategy = csA;
break;
case "typeB":
ConcreteStrategyB csB = new ConcreteStrategyB();
strategy = csB;
break;
case "typeC":
ConcreteStrategyC csC = new ConcreteStrategyC();
strategy = csC;
break;
}
}
//上下文接口
public void ContextInterface(){
strategy.strategy();
}
}

单一职责原则

就一个类而言,应该只有一个引起它变化的原因
如果一个类承载的职责过多,就等于把这些职责耦合在一起,一个职责变化可能就会削弱这个类完成其他职责的能力,这种耦合会导致脆弱的设计
软件设计真正要做的许多内容,就是发现职责并把那些职责相互分离,如果能想到多于一个的动机去改变一个类,那么这个类就具有多个职责,就应该考虑做职责分离

开放-封闭原则

开放-封闭原则就是说软件实体(类,模块,函数等)应该可以扩展,但是不可修改,就是说对于扩展是开放的,对于更改是封闭的
在我们最初编写代码的时候,假设变化不会发生,当变化发生时,我们就创建抽象来隔离以后发生的同类变化
开放-封闭原则是面向对象设计的核心所在,遵循这个原则可以使程序的设计可维护、可扩展、可复用、灵活性好
开发人员应该针对程序中频繁变化的部分抽象,然而并不是要对每个部分都刻意的进行抽象,拒绝不成熟的抽象同样重要

依赖倒转原则

抽象不应该依赖于细节,细节应该依赖于抽象,也就是要针对接口编程,不要对实现编程
高层模块不应该依赖于低层模块,两者都应该依赖于抽象

里氏代换原则

子类型必须能够替换掉它们的父类型
一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别,也就是说,在软件里,把父类都替换成它的子类,程序的行为没有变化

装饰模式

动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活
当系统中的部分方法和逻辑,只在一些特定情况下才会去执行,可以考虑使用装饰模式,把每个要装饰的功能放在单独的类中,并让这个类包装它所需要装饰的对象,当需要执行特殊行为时,就可以在运行时根据需要有选择的、按顺序的使用装饰功能包装对象了
装饰模式的优点是,把类中的装饰功能从类中移出,这样可以简化原有的类,有效把类的核心职责和装饰职责区分开,而且可以去除相关类中的重复装饰逻辑
需要注意的是,装饰模式的装饰顺序很重要,最理想的情况是保证装饰类之间彼此独立

装饰模式示例

1
2
3
abstract class Component{
public abstract void Operation();
}
1
2
3
4
5
class ConcreteComponent : Component{
public override void Operation(){
//具体对象的操作
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//装饰者
abstract class Decorator : Component{
protected Component component;

//设置要装饰的元件
public void SetComponent(Component component){
this.component = component;
}

//重写Operation,执行具体Component的Operation
public override void Operation(){
if(component != null){
component.Operation();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
//具体装饰A
class ConcreteDecoratorA : Decorator{
private string addedState;

//首先运行原Component的Operation(),再执行本类的功能,相当于对原Component进行了装饰
public override void Operation(){
base.Operation();
addedState = "New State";
//具体装饰对象A的操作
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//具体装饰B
class ConcreteDecoratorB : Decorator{

//首先运行原Component的Operation(),再执行本类的功能,相当于对原Component进行了装饰
public override void Operation(){
base.Operation();
AddedBehavior();
//具体装饰对象B的操作
}

private void AddedBehavior(){
//本类独有的方法
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
ConcreteComponent c = new ConcreteComponent();
ConcreteDecoratorA d1 = new ConcreteDecoratorA();
ConcreteDecoratorB d2 = new ConcreteDecoratorB();

/*
装饰的过程是:
1. 用ConcreteComponent实例化对象c
2. 用ConcreteDecoratorA的实例化对象d1来装饰c
3. 用ConcreteDecoratorB的实例化对象d2来包装d1
4. 执行d2的Operation()
*/
d1.SetComponent(c);
d2.SetComponent(d1);
d2.Operation();

代理模式

为其他对象提供一种代理以控制对这个对象的访问
代理模式的使用场合:
远程代理 为一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实
虚拟代理 根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象
安全代理 用来控制真实对象访问时的权限
智能引导 当调用真实的对象时,代理处理另外一些事情

代理模式示例:代理送礼物

1
2
3
4
5
6
//送礼物的接口
interface GiveGift{
void GiveDolls();
void GiveFlowers();
void GiveChocolate();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//实际的追求者
class Pursuit : GiveGift{
SchoolGirl mm;
public Pursuit(SchollGirl mm){
this.mm = mm;
}
public void GiveDolls(){
//送洋娃娃
}
public void GiveFlowers(){
//送鲜花
}
public void GiveChocolate(){
//送巧克力
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//追求者的代理
//保存一个引用使代理可以访问实体,并使用和真实实体相同的接口,这样代理就可以用来替代实体
class Proxy : GiveGift{
Pursuit gg;
public Proxy(SchoolGirl mm){
gg = new Pursuit(mm);
}
//调用 追求者 类的相关方法
public void GiveDolls(){
gg.GiveDolls();
}
public void GiveFlowers(){
gg.GiveFlowers();
}
public void GiveChocolate(){
gg.GiveChocolate();
}
}
1
2
3
4
5
6
7
8
9
//实际使用
SchoolGirl jiaojiao = new SchoolGirl();
jiaojiao.Name = "李娇娇";

Proxy daili = new Proxy(jiaojiao);

daili.GiveDolls();
daili.GiveFlowers();
daili.GiveChocolate();

工厂方法模式

定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类
工厂方法模式可以说是简单工厂模式的进一步抽象
相对于简单工厂,简单工厂的工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态的实例化相关的类,对于客户端来说,去除了和具体产品的依赖,但是缺点是,但需要添加新的功能时,必须要修改工厂类,违背了开放-封闭原则
根据依赖倒转原则,把工厂类抽象出一个接口,然后用所有需要生产具体类的工厂去实现这个接口,这样就不需要修改原有的工厂类,只需要添加相应的类和具体的工厂就可以了

工厂方法模式示例:算数运算实现

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
//运算符类
public class Operation{
private double _numberA = 0;
private double _numberB = 0;

public double NumberA{
get { return _numberA; }
set { _numberA = value; }
}
public double NumberB{
get { return _numberB; }
set { _numberB = value; }
}
//虚方法,用于子类定义自己的实现
public virtual double GetResult(){
double result = 0;
return result;
}
}
//加法类
public class OperationAdd : Operation{
public override double GetResult(){
double result = 0;
result = NumberA + NumberB;
return result;
}
}
//减法类
public class OperationSub : Operation{
public override double GetResult(){
double result = 0;
result = NumberA - NumberB;
return result;
}
}
1
2
3
4
//工厂接口
interface IFactory{
Operation CreateOperation();
}
1
2
3
4
5
6
7
8
9
10
11
//各运算符的工厂
class AddFactory : IFactory{
public Operation CreateOperation(){
return new OperationAdd();
}
}
class SubFactory : IFactory{
public Operation CreateOperation(){
return new OperationSub();
}
}
1
2
3
4
5
6
//调用代码
IFactory operFactory = new AddFactory();
Operation oper = operFactory.CreateOperation();
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();

原型模式

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
原型模式其实就是从一个对象再创建另一个可定制的对象,而且不需要知道任何创建的细节
一般在初始化信息不变的情况下,克隆是最好的办法,这既隐藏了对象创建的细节,又对性能是大大的提高
它等于说是不用重复初始化对象,而是动态的获得对象运行时的状态

原型模式示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//原型类
abstract class Prototype{
private string id;

public Prototype(string id){
this.id = id;
}

public string Id{
get { return id; }
}

//抽象类关键就是有这样一个克隆方法
public abstract Prototype Clone();
}
1
2
3
4
5
6
7
8
9
10
11
//具体原型类
class ConcretePrototype1 : Prototype{
public ConcretePrototype1(string id) : base(id){

}

public override Prototype Clone(){
//这里用的.NET的方法
return (Prototype)this.MemberwiseClone();
}
}
1
2
ConcretePrototype1 p1 = new ConcretePrototype1("1");
ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();

模板方法模式

定义一个操作中的算法框架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
既然使用了继承,就应该要成为子类的模板,所有重复的代码都应该上升到父类去,而不是让每个子类都重复定义,当我们要完成在某一层次一致的若干过程,但是其个别层次上的实现可能不同的时候,我们通常考虑用模板方法模式来处理
模板方法模式通常是通过把不变的行为转移到父类,去除子类中的重复代码

模板方法模式示例代码

1
2
3
4
5
6
7
8
9
10
//抽象模板
abstract class AbstractClass{
public abstract void PrimitiveOperation1();
public abstract void PrimitiveOperation2();

public void TemplateMethod(){
PrimitiveOperation1();
PrimitiveOperation2();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ConcreteClassA : AbstractClass{
public override void PrimitiveOperation1(){
//具体类A方法1实现
}
public override void PrimitiveOperation2(){
//具体类A方法2实现
}
}

class ConcreteClassB : AbstractClass{
public override void PrimitiveOperation1(){
//具体类B方法1实现
}
public override void PrimitiveOperation2(){
//具体类B方法2实现
}
}
1
2
3
4
5
6
7
//具体调用
AbstractClass c;
c = new ConcreteClassA();
c.TemplateMethod();

c = new ConcreteClassB();
c.TemplateMethod();

迪米特法则

迪米特法则,也叫最少知识原则,如果两个类不必彼此直接通信,那么这两个类就不应该发生直接的相互引用,如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用
迪米特法则根本思想是强调了类之间的松耦合,类之间的耦合越弱,越有利于复用,一个处于弱耦合的类被修改,不会对有关系的类造成波及,也就是说,信息的隐藏促进了软件的复用

外观模式

为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用,外观模式是非常常用的模式之一
外观模式的使用场景:

  1. 在设计初期,应该有意识的将不同的两个层分离,层与层之间建立外观Facade,这样可以为复杂的子系统提供一个简单的接口,使得耦合降低
  2. 在开发阶段,子系统往往因为不断重构演化变的越来越复杂,增加Facade可以减少它们之间的依赖
  3. 在维护一个遗留的大型项目时,可能这个系统已经非常难以维护和扩展,但因为它包含非常重要的功能,新的需求必须依赖它,这个时候用外观模式Facade,可以为新系统开发一个Facade类,来提供设计粗糙或者高度复杂的遗留代码的比较清晰简单的接口,让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作

外观模式示例代码

1
2
3
4
5
6
7
8
9
10
class SubSystemOne{
public void MethodOne(){
//子系统方法1
}
}
class SubSystemTow{
public void MethodTwo(){
//子系统方法2
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//外观类
class Facade{
SubSystemOne one;
SubSystemTwo two;

public Facade(){
one = new SubSystemOne();
two = new SubSystemTwo();
}

public void MethodA(){
one.MethodOne();
two.MethodTwo();
}

public void MethodB(){
two.MethodTwo();
}
}
1
2
3
4
5
//调用方式
Facade facade = new Facade();

facade.MethodA();
facade.MethodB();

建造者模式

又叫生成器模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
如果需要将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,这个时候就可以用建造者模式,如果用了建造者模式,那么用户只需要指定需要创建的类型就可以得到它们,而具体建造的过程和细节就不需要知道了
建造者模式的几个概念:

  1. Builder 是为创建一个Product对象的各个部件指定的抽象接口
  2. ConcreteBuilder 具体的建造者,实现Builder接口,构造和装配各个部件
  3. Product 具体的产品
  4. Director 指挥者 构建一个使用Builder接口的对象
    建造者模式的好处就是使得建造代码与表示代码分离,当需要改变一个产品的内部表示的时候,只需要再定义一个具体的建造者就可以了
    建造者模式是在当穿件复杂对象的算法应该独立于该对象的组成部分以及它们的装配方法时适用的模式

建造者模式示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//产品类,由多个部件组成
class Product{
IList<string> parts = new List<string>();

public void Add(string part){
parts.Add(part);
}

public void Show(){
foreach(string part in parts){
//show part
}
}
}
1
2
3
4
5
6
//抽象建造者类,确定产品由两个部件PartA和PartB组成
abstract class Builder{
public abstract void BuildPartA();
public abstract void BuildPartB();
public abstract Product GetResult();
}
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
//具体建造者1
class ConcreteBuilder1 : Builder{
private Product product = new Product();

public override void BuilderPartA(){
product.Add("部件A");
}

public override void BuilderPartB(){
product.Add("部件B");
}

public override Product GetResult(){
return product;
}
}

//具体建造者2
class ConcreteBuilder2 : Builder{
private Product product = new Product();

public override void BuilderPartA(){
product.Add("部件X");
}

public override void BuilderPartB(){
product.Add("部件Y");
}

public override Product GetResult(){
return product;
}
}
1
2
3
4
5
6
7
//指挥者类
class Director{
public void Construct(Builder builder){
builder.BuilderPartA();
builder.BuilderPartB();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
//调用方式
Director director = new Director();
Builder b1 = new ConcreteBuilder1();
Builder b2 = new ConcreteBuilder2();

director.Construct(b1);
Product p1 = b1.GetResult();
p1.Show();

director.Construct(b2);
Product p2 = b2.GetResult();
p2.Show();

观察者模式

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使得它们能够自动更新自己
但是,观察者模式将一个系统分割成一系列相互协作的类有一个很不好的副作用,就是需要维护相关对象间的一致性,我们不希望为了维持一致性而使得各类紧密耦合,这样会给维护、扩展和重用都带来不便
观察者模式的使用:
当一个对象的改变需要同时改变其他对象的时候,而且它不知道具体有多少个对象待改变
当一个抽象模型有两个方面,其中一个方面依赖于另一个方面
总的来讲,观察者模式所做的工作其实就是在解除耦合,让耦合的双方都依赖于抽象,从而使得各自的变化都不会影响另一边的变化

观察者模式示例代码

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
/*
抽象通知者,一般用一个抽象类或者一个接口实现,它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者
抽象主题提供一个接口,可以增加和删除观察者对象
*/
abstract class Subject{
private IList<Observer> observers = new List<Observer>();

//增加观察者
public void Attach(Observer observer){
observers.Add(observer);
}
//移除观察者
public void Detach(Observer observer){
observers.Remove(observer);
}
//通知
public void Notify(){
foreach(Observer o in observers){
o.Update();
}
}
}

/*
具体通知者,将有关状态存入具体观察者对象
*/
class ConcreteSubject : Subject{
private string subjectState;

public string SubjectState{
get { return subjectState; }
set { subjectState = value; }
}
}
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
/*
抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己
*/
abstract class Observer{
public abstract void Update();
}

/*
具体观察者,实现抽象观察者所要求的更新接口
*/
class ConcreteObserver : Observer{
private string name;
private string observerState;
private ConcreteSubject subject;

public ConcreteObserver(ConcreteSubject subject, string name){
this.subject = subject;
this.name = name;
}

public override void Update(){
observerState = subject.SubjectState;
}

public ConcreteSubject Subject{
get{ return subject; }
set{ subject = value; }
}
}
1
2
3
4
5
6
7
8
9
//调用代码
ConcreteSubject s = new ConcreteSubject();

s.Attach(new ConcreteObserver(s, "X"));
s.Attach(new ConcreteObserver(s, "Y"));
s.Attach(new ConcreteObserver(s, "Z"));

s.SubjectState = "ABC";
s.Notify();

但是观察者模式也有一些不足,比如
抽象通知者还是依赖于抽象观察者,如果没有抽象观察者这样的接口,通知功能就没法完成
每个具体的观察者,不一定是“Update”方法需要调用

事件委托方式实现

事件委托方式可以让抽象通知者不需要依赖于抽象观察者,由客户端来决定通知谁

事件委托方式示例:老板回来了
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
//看股票的同事
class StockObserver{
private string name;
private Subject sub;
public StockObserver(string name, Subject sub){
this.name = name;
this.sub = sub;
}

public void CloseStockMarket(){
//关闭股票行情
}
}

//看NBA的同事
public NBAObserver{
private string name;
private Subject sub;
public NBAObserver(string name, Subject sub){
this.name = name;
this.sub = sub;
}

public void CloseNBADirectSeeding(){
//关闭NBA直播
}
}
1
2
3
4
5
6
7
8
9
10
11
//通知者接口
interface Subject{
void Notify();
string SubjectState{
get;
set;
}
}

//声明一个委托
delegate void EventHndler();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//老板类
class Boss : Subject{
//声明一个事件 Update,类型为委托EventHandler
public event EventHandler Update;

private string action;

public void Notify(){
//在访问时,调用 Update
Update();
}
public string SubjectState{
get{ return action; }
set{ action = value; }
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//调用代码
Boss boss = new Boss();

//看股票的同事
StockObserver tongshi1 = new StockObserver("同事1", boss);
//看NBA的同事
NBAObserver tongshi2 = new NBAObserver("同事2", boss);

//将观察者的具体方法挂钩到通知者的 Update 方法中,也就是将不同类的不同方法委托给 通知者的 Update 方法了
boss.Update += new EventHandler(tongshi1.CloseStockMarker);
boss.Update += new EventHandler(tongshi2.CloseNBADirectSeeding);

//通知
boss.SubjectState = "老板回来啦!";
boss.Notify();

委托就是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为,委托方法的使用可以像其他任何方法一样,具有参数和返回值,委托可以看做是对函数的抽象,是函数的“类”,委托的实例将代表一个具体的函数
一个委托可以搭载多个方法,所有方法将依次唤起,更重要的是,它可以使得委托对象所搭载的方法并不需要属于同一个类
需要注意的是,委托对象所搭载的所有方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值类型

抽象工厂模式

抽象工厂模式是提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
抽象模式最大的好处是易于交换产品系列,由于具体工厂类在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变的很容易,它只需要改变具体工厂即可使用不同的产品配置
第二个好处是,它让具体的创建实例过程和客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中

抽象工厂模式示例:多数据库配置

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
//访问部门表的抽象工厂接口
interface IDepartment{
void Insert(Department department);

Departmaent GetDepartment(int id);
}

//用于访问Sql Server的Department
class SqlserverDepartment : IDepartment{
public void Insert(Department department){
//插入部门
}

public Department GetDepartment(int id){
//获取部门
}
}

//用于访问Access的Department
class AccessDepartment : IDepartment{
public void Insert(Department department){
//插入部门
}

public Department GetDepartment(int id){
//获取部门
}
}
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
//访问用户表的抽象工厂接口
interface IUser{
void Insert(User user);

User GetUser(int id);
}

//用于访问Sql Server的User
class SqlserverUser : IUser{
public void Insert(User user){
//插入用户
}

public User GetUser(int id){
//获取用户
}
}

//用于访问Access的User
class AccessUser : IUser{
public void Insert(User user){
//插入用户
}

public User GetUser(int id){
//获取用户
}
}
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
//抽象工厂接口
interface IFactory{
IUser CreateUser();

IDepartment CreateDepartment();
}

class SqlServerFactory : IFactory{
public IUser CreateUser(){
return new SqlserverUser();
}

public IDepartment CreateDepartment(){
return new SqlserverDepartment();
}
}

class AccessFactory : IFactory{
public IUser CreateUser(){
return new AccessUser();
}

public IDepartment CreateDepartment(){
return new AccessDepartment();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//调用方法
User user = new User();
Department dept = new Department();

//只需要确定实例化哪一个数据库访问对象给Factory
IFactory factory = new AccessFactory();

IUser iu = new factory.CreateUser();
IDepartment id = facroty.CreateDepartment();

iu.Insert(user);
iu.GetUser(1);

id.Insert(dept);
id.GetDepartment(1);

状态模式

>