概述
大话设计模式
一.简单工厂模式
创建一个工厂对象,根据不同的需求创建不同的对象,这些对象又继承了同一个父类,父类里有一个抽象方法,这些子类重写了父类的这个方法。示例见P21、P27
商场收银系统
//现金收费抽象类
abstract class CashSuper
{
public abstract double acceptCash(double money);
}
//正常收费子类
Class CashNormal : CashSuper
{
public override double acceptCash(double money)
{
return money;
}
}
//打折收费子类
Class CashRebate : CashSuper
{
private double moneyRebate = 1d;//折扣,如八折:0.8
publc CashRebate(string moneyRebate)
{
this.moneyRebate=double.Parse(moneyRebate)
}
public override double acceptCash(double money)
{
return money * moneyRebate;
}
}
//返利收费子类
Class CashReturn : CashSuper
{
private double moneyCondition = 0.0d;
private double moneyReturn = 0.0d;
publc CashReturn(string moneyCondition, string moneyReturn)
{
this.moneyConditon=double.Parse(moneyCondition)
this.moneyReturn=double.Parse(moneyReturn)
}
public override double acceptCash(double money)
{
double result = money;
if(money >= moneyCondition)
result = money -Math.Floor(money/moneyCondition) * moneyReturn;
return result;
}
}
//现金收费工厂类
class CashFactory
{
public static CashSuper createCashAccept(string type)
{
CashSuper cs = null;
switch(type)
{
cast "正常收费":
cs = new CashNormal();
break;
cast "满300减100":
CashReturn cr1 = new CashReturn("300","100");
cs = cr1;
break;
cast "打八折":
CashRebate cr2 = new CashRebate("0.8");
cs = cr2;
break;
}
}
}
//客户端窗体程序
double total =0.0d;
private void btnOk_click(object sender,EventArgs e)
{
//工厂方法接收不同的折扣
CashSuper csuper= CashFactory.cerateCashAccept(cbxType.SelectedItem.ToString());
double totalPrices= 0d;
//计算总钱数
totalPrices = csuper.acceptCash(Convert.ToDouble(txtPrice.Text))*Convert.ToDouble(txtNum.Text));
total = total +totalPrices;
}
二.策略模式
简单工厂模式中不同的需求会有不同的算法(策略),将不同的算法抽象出一个抽象策略,具体的策略继承抽象策略,构建一个Context(上下文)类,其中的方法调用抽象策略的方法,构造参数为抽象策略,具体代码见P26
//构建Context
class CashContext
{
private CashSuper cs;
public CashContext(CashSuper csuper)
{
this.cs = csuper;
}
public double GetResult(double money)
{
return cs.acceptCash(money)
}
}
//客户端窗体程序
double total =0.0d;
private void btnOk_click(object sender,EventArgs e)
{
CashContext cc = null;
//工厂方法接收不同的折扣
switch (cbxType.SelectedItem.ToString())
{
cast "正常收费":
cc = new CashContext(new CashNormal());
break;
cast "满300减100":
cc = new CashContext(new CashReturn("300","100"));
break;
cast "打八折":
cc = new CashContext(new CashRebate("0.8"));
break;
}
double totalPrices= 0d;
//计算总钱数
totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text))*Convert.ToDouble(txtNum.Text));
total = total +totalPrices;
}
三.策略与简单工厂结合
和简单工厂类似,根据不同的需求创建不同的对象,不同的是,将创建完的对象赋给上下文拥有的父类,
再通过内部的方法调取父类的方法(这时已经是子类的方法)
//改造Context
class CashContext
{
CashSuper cs = null;
public CashContext(string type)
{
switch (type)
{
cast "正常收费":
CashNormal cs0 = new CashNormal();
cs =cs0
break;
cast "满300减100":
CashReturn cr1 = new CashReturn("300","100");
cs = cr1;
break;
cast "打八折":
CashRebate cr2 = new CashRebate("0.8");
cs = cr2;
break;
}
}
public double GetResult(double money)
{
return cs.acceptCash(money)
}
}
//客户端窗体程序
double total =0.0d;
private void btnOk_click(object sender,EventArgs e)
{
CashContext cc = new CashContext(cbxType.SelectedItem.ToString());
double totalPrices= 0d;
//计算总钱数
totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text))*Convert.ToDouble(txtNum.Text));
total = total +totalPrices;
}
四.开发-封闭原则
对于扩展是开放的,对于更改是封闭的
五.装饰模式
装饰模式就是构造一个装饰类,构造参数为将要进行装饰的对象,装饰类中的方法为装饰对象的方法,
然后具体的装饰的对象再继承装饰类,其中执行的方法可以进行制造装饰的顺序
class Person
{
public Person()
{}
private string name;
public Person(string name)
{
this.name=name;
}
public virtual void Show()
{
Console.WriteLine("装扮的{0}",name);
}
}
服饰类
class Finery:Person
{
protected Person component;
public void Decorate(Person component)
{
this.component = component;
}
public override void Show()
{
if(component!=null)
{
component.Show();
}
}
}
具体服饰类
class Tshirt:Finery
{
public override void Show()
{
Console.Write("大T恤")
base.Show();
}
}
class BigTrouser:Finery
{
public override void Show()
{
Console.Write("垮裤");
base.Show();
}
}
//其余类似,省略
static void Main(string[] args)
{
Person xc = new Person("小菜");
Console.WriteLine("n第一种装扮");
Sneaker pqx = new Sneakwers();
BigTrouser kk = new BigTrouser();
TShirts dtx = new TShirts();
pqx.Decorate(xc);
kk.Decorate(pqx);
dtx.Decorate(kk);
dtx.Show();
}
六.代理模式
Subject类,定义了RealSubject和Proxy的共用接口,这样就在任何时候使用RealSubject的地方都可以使用Proxy。
abstract class Subject
{
public abstract void Request();
}
RealSubject类,定义Proxy 所代表的真实实体
class RealSubject : Subject
{
public override void Request()
{
Console.WriteLine("真实的请求");
}
}
Proxy类,保存一个引用使得代理可以访问实体,并提供一个与Subject 的接口相同的接口,这样代理就可以用来代替实体。
class Proxy :Subject
{
RealSubject realSubject;
public overlide ovid Request()
{
if(realSubject ==null)
{
realSubject=new RealSubject();
}
realSubject.Request();
}
}
客户端代码
static void Main(string[] args)
{
Proxy proxy = new Proxy();
proxy.Request();
Console.Read();
}
七.工厂方法模式
工厂方法对简单工厂又进行了进一步拆分,不同的工厂类实现同一个工厂接口,重写工厂接口的方法,创建不同的代理对象(大学生和社区志愿者都是雷锋的代理,都继承了雷锋)
//雷锋工厂
interface IFactory
{
LeiFeng CreateLeiFeng();
}
//学雷锋的大学生工厂
class UndergraduateFactory :IFactory
{
public LeiFeng CreateLeiFeng()
{
return new Undergraduate();
}
}
//社区志愿者工厂
class VolunteerFactory :IFactory
{
public LeiFeng CreateLeiFeng()
{
return new Volunteer();
}
}
//客户端调用
//工厂方法模式
IFactory factory = new UndergraduateFactory();
LeiFeng student = factory.CreateLeiFeng();
student.BuyRice();
student.Sweep();
student.Wash();
八.原型模式
创建当前对象的浅表副本。方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其副本引用同一对象。
浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
//工作经历类
class WorkExperience
{
private string WorkDate;
public string WorkDate;
{
get {return WorkDate;}
set {workDate = value}
}
private string company;
public string Company
{
get{return company;}
set{company = value;}
}
}
//简历类
class Resume : ICloneable
{
private string name;
private string age;
private string sex;
private WorkExperience work;
public Resume(string name)
{
this.name=name;
work=new WorkExperience();
}
//设置个人信息
public void SetPersonalInfo(string sex,string age)
{
this.sex = sex;
this.age = age;
}
//设置工作经历
public void SetWorkExperience(string workDate,string company)
{
work.WorkDate = workDate;
work.Company = company;
}
//显示
public void Display()
{
Console.WriteLine("{0} {1} {2}",name,sex,age);
Console.WriteLine("工作经历:{0} {1}",work.WorkDate,work.Company);
}
public Object Clone()
{
return (Object)this.MemberwiseClone();
}
}
//客户端代码
static void Main (string[] args)
{
Resume a = new Resume("大鸟");
a.SetPersonalInfo("男","29");
a.SetWorkExperience("1998-2000","XX公司");
Resume b = (Resume)a.Clone();
b.SetWorkExperience("1998-2006","YY公司");
Resume c = (Resume)a.Clone();
c.SetPersonalInfo("男","24");
c.SetWorkExperience("1998-2003","zz公司");
a.Display();
b.Display();
c.Display();
Console.read();
}
//结果
大鸟 男 29
工作经历 1998-2003 ZZ企业
大鸟 男 29
工作经历 1998-2003 ZZ企业
大鸟 男 24
工作经历 1998-2003 ZZ企业
深复制:把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
//工作经历类
class WorkExperience : ICloneable
{
private string WorkDate;
public string WorkDate;
{
get {return WorkDate;}
set {workDate = value}
}
private string company;
public string Company
{
get{return company;}
set{company = value;}
}
public Object Clone()
{
return (Object)this.MemberwiseClone();
}
}
//简历类
class Resume : ICloneable
{
private string name;
private string age;
private string sex;
private WorkExperience work;
public Resume(string name)
{
this.name=name;
work=new WorkExperience();
}
private Resume(WorkExperience work)
{
this.work = (WorkExperience)work.Clone();
}
//设置个人信息
public void SetPersonalInfo(string sex,string age)
{
this.sex = sex;
this.age = age;
}
//设置工作经历
public void SetWorkExperience(string workDate,string company)
{
work.WorkDate = workDate;
work.Company = company;
}
//显示
public void Display()
{
Console.WriteLine("{0} {1} {2}",name,sex,age);
Console.WriteLine("工作经历:{0} {1}",work.WorkDate,work.Company);
}
public Object Clone()
{
Resume a = new Resume(this.work);
obj.name=this.name;
obj.sex=this.sex;
obj.age=this.age;
return obj;
}
}
//客户端代码
static void Main (string[] args)
{
Resume a = new Resume("大鸟");
a.SetPersonalInfo("男","29");
a.SetWorkExperience("1998-2000","XX公司");
Resume b = (Resume)a.Clone();
b.SetWorkExperience("1998-2006","YY公司");
Resume c = (Resume)a.Clone();
c.SetPersonalInfo("男","24");
c.SetWorkExperience("1998-2003","zz公司");
a.Display();
b.Display();
c.Display();
Console.read();
}
//结果
大鸟 男 29
工作经历 1998-2000 XX企业
大鸟 男 29
工作经历 1998-2006 YY企业
大鸟 男 24
工作经历 1998-2003 ZZ企业
九.模板方法模式
将相同的代码都抽取出来,当具体的实现细节不同时要抽取一个方法,具体示例见P95
十.迪米特法则
如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
此法则首先强调的前提是在类的结构设计上,每一个类都应当尽量降低成员的访问权限,也就是说,一个类包装好自己的private状态,不需要让别的类知道的字段或行为就不要公开。
十一.依赖倒转原则
A.高层模块不应该依赖底层模块。两个都应该依赖抽象。
B.抽象不应该依赖细节。细节应该依赖抽象。
十二.里氏代换原则
子类型必须能够代替掉它们的父类型
子类型拥有父类型所有的非private的行为和属性
十三.外观模式
为子系统的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
//四个子系统的类
class SubSystemOne
{
public void MethodOne()
{
Console.WriteLine("子系统方法一");
}
}
class SubSystemTwo
{
public void MethodTwo()
{
Console.WriteLine("子系统方法二");
}
}
class SubSystemThree
{
public void MethodThree()
{
Console.WriteLine("子系统方法三");
}
}
class SubSystemFour
{
public void MethodFour()
{
Console.WriteLine("子系统方法四");
}
}
//外观类 它需要了解所有的子系统的方法和属性,进行组合,以备外界调用
class Facade
{
SubSystemOne one;
SubSystemTwo two;
SubSystemThree three;
SubSystemFour four;
public Facade()
{
one = new SubSystemOne();
two = new SubSystemTwo();
three = new SubSystemThree();
four = new SubSystemFour();
}
public void MethodA()
{
Console.WriteLine("方法组A")
one.MethodOne();
two.MethodTwo();
four.MethodFour();
}
public void MethodB()
{
Console.WriteLine("方法组B")
two.MethodTwo();
three.MethodThree();
Console.Read();
}
}
//客户端调用 由于facade的作用,客户端可以根本不知道三个子系统的存在
static void Main(string[] args)
{
Facade facade = new Facade();
facade.MethodA();
facade.MethodB();
Console.Read();
}
何时使用外观模式?
1.在设计初级阶段,应该要有意识的将不同的两个层分离,比如经典的三层架构,就需要考虑在数据访问层和业务逻辑层、业务逻辑层和表示层的层与层之间建立Facade,这样可以为复杂的子系统提供一个简单的接口,使得耦合大大降低。
2.在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,增加外观facade可以提供一个简单的接口,减少它们之间的依赖。
3.在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,可以为新系统开发一个外观facade类,来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口,让新系统和Facade对象交互,Facade与遗留代码交互所有复杂的工作。
十四.建造者模式
主要用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。
Project类——产品类,由多个部件组成
class Product
{
List<string> parts = new List<string>();
public void Add(string part){
parts.Add(part);
}
public void Show(){
Console.WriteLine("产品创建")
foreach(string part in parts)
{
Console.WriteLine(part);
}
}
}
//Builder类——抽象构造者,确定产品由两个部件PartA和PartB组成,并声明一个得到产品建造后结果的方法GetResult。
abstract class Builder
{
public abstract void BuildPartA();
public abstract void BuildPartB();
public abstract Product GetResult();
}
ConcreteBuilder1类——具体建造类
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;
}
}
ConcreteBuilder2类——具体建造类
class ConcreteBuilder1: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;
}
}
Director类——指挥者类
class Director
{
public void Construct(Builder builder)
{
builder.BuilderPartA();
builder.BuilderPartB();
}
}
//客户端代码,客户不需知道具体的建造过程
static void Main(string[] args)
{
Director director = new Director();
Builder b1 = new ConcreteBuilder1();
Builder b2 = new ConcreteBulider2();
director.Construct(b1);
Product p1 = b1.getResult();
p1.show();
director.Construct(b2);
Product p2 = b2.getResult();
p2.show();
Console.Read();
}
十五.观察者模式
观察者模式又叫发布-订阅模式
其定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有的观察者对象,使它们能够自动更新自己。
其所做的工作就是在解除耦合。让耦合的双方都依赖于抽象而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。
抽象通知者接口
//通知者接口
interface Subject
{
void Attach(Observer observer);
void Detach(Observer observer);
void Notify();
string SubjectState
{
get;
set;
}
}
具体的通知者类可能是前台,也可能是老板,它们也许有各自的一些方法,但对于通知者来说,它们是一样的,所以它们都去实现这个接口。
class Boss:Subject
{
//同事列表
private List<Observer> observers = new List<Observer>();
private string action;
//增加
public void Attach(Observer observer)
{
obsrever.Add(observer);
}
//减少
public void Detach(Observer observer)
{
obsrever.Remove(observer);
}
//通知
public void Notify()
{
foreach(Observer o in observer)
o.Update();
}
//老板状态
public string SubjectState
{
get{return action;}
set{action = value;}
}
}
前台秘书类和老板类类似,略。
对于具体的观察者,需要更改的地方就是把与‘前台’耦合的地方都改成针对抽象通知者。
//抽象观察者
abstract class Observer
{
protected string name;
protected Subject sub;
public Observer(string name,Subject sub)
{
this.name = name;
this.sub = sub;
}
public abstract void Update();
}
//看股票的同事
class StockObserver : Observer
{
public StockObserver(string name,Subject sub)
{
:base(name,sub)
}
public override void Update()
{
Console.WriteLine("{0} {1} 关闭股票行情,继续工作!",sub.SubjectState,name);
}
}
//客户端代码如下:
//老板胡汉三
Boss huansan = new Boss();
//看股票的同事
StockObserver tongshi1 = new StockObserver("魏关姹",huhansan);
//看NBA的同事
NBAbserver tongshi2 = new NBAObserver("易官查",huhansan);
huhuansan.Attach(tongshi1);
huhuansan.Attach(tongshi2);
//魏关姹 其实没有被老板通知到,所以减去
huhuansan.Detach(tongshi1);
//老板回来
huhansan.SubjectState = "我胡汉三回来了";
//发出通知
huhansan.Notify();
//运行结果
我胡汉三回来了,易官查 关闭NBA直播,继续工作!
缺点:
尽管已经用了依赖倒转原则,但是‘抽象通知者还是依赖于‘抽象观察者’,这时事件委托实现就应运而生了。
十六.事件委托实现
'‘看股票观察者’'类和看“NBA观察者”类,去掉了父类“抽象观察类”,所以补上一些代码,并将“更新”方法名改为各自适合的方法名。
//看股票的同事
class StockObserver
{
private string name;
protected Subject sub;
public StockObserver(string name,Subject sub)
{
this.name = name;
this.sub = sub;
}
public override void CloseStockMarket()
{
Console.WriteLine("{0} {1} 关闭股票行情,继续工作!",sub.SubjectState,name);
}
}
//看NBA的同事
class NBAObserver
{
private string name;
protected Subject sub;
public NBAObserver(string name,Subject sub)
{
this.name = name;
this.sub = sub;
}
public override void CloseNBADirectSeeding()
{
Console.WriteLine("{0} {1} 关闭NBA直播,继续工作!",sub.SubjectState,name);
}
}
//通知者接口
interface Subject
{
void Notify();
string SubjectState
{
get;
set;
}
}
//声明一个委托,名称叫“EventHandler(事件处理程序)”,无参数,无返回值。
delegate void EventHandler();
//老板类和前台秘书类
class Boss:Subject
{
//声明一事件update,类型为委托EventHandler
//声明一“EventHandler(事件处理程序)”的委托事件,名称交“Update(更新)”
public event EventHandler Update;
private string action;
//通知
public void Notify()
{
Update();
}
//老板状态
public string SubjectState
{
get{return action;}
set{action = value;}
}
}
class Secretary:Subject
{
//与老板类类似,省略
}
//客户端代码
//老板胡汉三
Boss huhansan = new Boss();
//看股票的同事
StockObserver tongshi1 = new StockObserver("魏关姹",huhansan);
//看NBA的同事
NBAObserver tongshi2 = new NBAObserver("易管查",huhansan);
//将“看股票者”的关闭股票程序方法和看“NBA者”的关闭NBA直播的方法挂钩到老板的更新上,也就是将两不同类的不同方法委托给老板类的更新了。
huhansan.Update += new EventHandler(tongshi1.CloseStockMarket);
huhansan.Update += new EventHandler(tongshi2.CloseNBADirectSeeding);
//显示结果
我胡汉三回来了,魏关姹 关闭股票行情,继续工作!
我胡汉三回来了,易管查 关闭NBA直播,继续工作!
委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的“类”,委托的实例将代表一个具体的函数。
一个委托可以搭载多个方法,所有的方法被依次唤起。更重要的是,它可以使得委托对象所搭载的方法并不需要属于同一个类。
但委托也是有前提的,那就是委托对象所搭载的方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值类型。
十七.抽象工厂模式
interface Department
{
void Insert(Department department);
Department GetDepartment(int id);
}
//SqlserverDepartment类,用于访问SQLServer的Department。
class SqlserverDepartment:Department
{
public void Insert(Department department)
{
Console.WriteLine("在SQLServer中给Department表增加一条记录");
}
public Department GetDepartment(int id)
{
Console.WriteLine("在SQLServer中根据id得到Department表的一条记录");
}
}
//AccessDepartment类,用于访问Access的Department。
class AccessDepartment类:Department
{
public void Insert(Department department)
{
Console.WriteLine("在Access中给Department表增加一条记录");
}
public Department GetDepartment(int id)
{
Console.WriteLine("在Access中根据id得到Department表的一条记录");
}
}
//Ifactory 接口 定义一个创建访问Department表对象的抽象的工厂接口
interface Factory
{
User CreateUser();
Department CreateDepartment();
}
//SqlServerFactory类,实现Factory 接口,实例化SqlserverUser 和SqlserverDepartment
class SqlServerFactory : Factory
{
public User CreateUser()
{
return new SqlserverUser();
}
public Department CreateDepartment()
{
return new SqlserverDepartment();
}
}
//AccessFactory类,实现Factory 接口,实例化AccessUser 和AccessDepartment
class AccessFactory : Factory
{
public User CreateUser()
{
return new AccessUser();
}
public Department CreateDepartment()
{
return new AccessDepartment();
}
}
//客户端代码
static void Main(string[] args)
{
User user = new User();
Department dept = new Department();
//Factory factory = new SqlServerfactory();
Factory factory = new AccessFactory();
User iu = factory.CreateUser();
iu.Insert(user);
iu.GetUser(1);
Departmnet id = factory.CreateDepartment();
id.Insert(dept);
id.GetDepartment(1);
Console.Read();
}
//结果显示如下
在Access中给User表添加一条记录
在Access中根据id得到user表的一条记录
在Access中给Department表添加一条记录
在Access中根据id得到Department表的一条记录
优点:
1.易于交换产品系列,由于具体工厂类,例如Factory factory = new AccessFactory(),在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,他需要改变具体工厂即可使用不同的产品配置。我们的设计不能去防止需求的更改,那么我们的目的是让改动变得最小。
2.它让具体的创建实例过程与客户端分离,客户端是通过他们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码中。
缺点:
1.如果现在要增加项目表Project ,需要改动很多类
2.在客户端很多地方都用到User和Department,而每次使用这个类都需要先声明Factory factory = new SqlserverFactory();如果有100次调用,就会有100次改动Factory factory = new AccessFactory();
简单工厂来改进抽象工厂
class DataAccess
{
private static readonly string db = "Sqlserver";
//private static readonly string db = "Access";
public static User CreateUser()
{
User result = null;
switch(db)
{
case "Sqlserver":
result = new SqlServerUser();
break;
case "Access":
result = new AccessUser();
break;
}
return result;
}
public static Department CreateDepartment()
{
Department result = null;
switch(db)
{
case "Sqlserver":
result = new SqlServerDepartment();
break;
case "Access":
result = new AccessDepartment();
break;
}
return result;
}
}
//客户端代码
static void Main(string[] args)
{
User user = new User();
Department dept = new Department();
//直接得到实际的数据库访问实例,而不存在任何的依赖
User iu = DataAccess.CreateUser();
iu.Insert(user);
iu.GetUser(1);
Departmnet id = DataAccess.CreateDepartment();
id.Insert(dept);
id.GetDepartment(1);
Console.Read();
}
如果需要增加Oracle数据库访问,原来抽象工厂只增加一个OracleFactory工厂类就可以了,现在需要在DataAccess类中每个方法的switch中加case了。
用反射+抽象工厂的数据访问程序
反射格式
Assembly.Load(“程序集名称”).CreateInstance(“命名空间.类名称”)
//常规写法
User result = new SqlserverUser();
//反射的写法
using System.Reflection;
User result = (User)Assembly.Load("抽象工厂模式").CreateInstance("抽象工厂模式.SqlserverUser");
class DataAccess
{
private static readonly string AssemblyName = "抽象工厂模式";
private static readonly string db = "Sqlserver";
public static User CreateUser()
{
string className = AssemblyName+"."+db+"User";
return (User)Assembly.Load(AssemblyName).CreateInstance(className);
}
public static Department CreateDepartment()
{
string className = AssemblyName+"."+db+"User";
return (User)Assembly.Load(AssemblyName).CreateInstance(className);
}
}
//如果增加Oracle数据库
更改 private static readonly string db = "Sqlserver"; → private static readonly string db = "Oracle";
//db采用在配置文件中配置即可
十八.状态模式
如果条件分支过多时,将条件分支拆分出来,用一个类代替
抽象状态类,定义一个抽象方法“写程序”
//抽象状态
public abstract class State
{
public abstract void WriteProgram(Work w);
}
//上午工作状态
public class ForenoonState : State
{
public override void WriteProgram (Work w)
{
if(w.Hour<12){
Console.WriteLine("当前时间:{0}点 上午工作,精神百倍",w.Hour);
}
else
{
w.SetState(new NoonState());
w.WriteProgram();
}
}
}
//中午工作状态
public class NoonState : State
{
public override void WriteProgram (Work w)
{
if(w.Hour<13){
Console.WriteLine("当前时间:{0}点 饿了,午饭;犯困,午休",w.Hour);
}
else
{
w.SetState(new AfternoonState());
w.WriteProgram();
}
}
}
//下午工作状态
public class AfternoonState : State
{
public override void WriteProgram (Work w)
{
if(w.Hour<17){
Console.WriteLine("当前时间:{0}点 下午状态还不错,继续努力",w.Hour);
}
else
{
w.SetState(new EveningState());
w.WriteProgram();
}
}
}
//晚间工作状态
public class EveningState : State
{
public override void WriteProgram (Work w)
{
if(w.TaskFinished){
w.SetState(new RestState());
w.WriteProgram();
}
else
{
if(w.Hour<21)
{
Console.WriteLine("当前时间:{0}点 加班哦,疲累之极",w.Hour);
}
else
{
w.SetState(new SleepingState());
w.WriteProgram();
}
}
}
}
//睡眠状态
public class SleepingState : State
{
public override void WriteProgram (Work w)
{
if(w.Hour<17){
Console.WriteLine("当前时间:{0}点 下午状态还不错,继续努力",w.Hour);
}
else
{
w.SetState(new EveningState());
w.WriteProgram();
}
}
}
//下班休息状态
public class RestState : State
{
public override void WriteProgram (Work w)
{
Console.WriteLine("当前时间:{0}点 下班回家了",w.Hour);
}
}
//工作
public class Work
{
private State current;
public Work()
{
current = new ForenoonState();
}
private double hour;
public double Hour;
{
get{return hour;}
set{hour = value}
}
private bool finish = false;
public bool TaskFinished
{
get{return finish;}
set{finish = value;}
}
public void SetState(State s)
{
current =s;
}
public void WriteProgram()
{
current.WriteProgram(this);
}
}
static void Main(string[] args)
{
//紧急项目
Work emergencyProjects = new Work();
emergencyProjects.Hour = 9;
emergencyProjects.WriteProgram();
emergencyProjects.Hour = 10;
emergencyProjects.WriteProgram();
emergencyProjects.Hour = 12;
emergencyProjects.WriteProgram();
emergencyProjects.Hour = 13;
emergencyProjects.WriteProgram();
emergencyProjects.Hour = 14;
emergencyProjects.WriteProgram();
emergencyProjects.Hour = 17;
emergencyProjects.TaskFinished=false;
emergencyProjects.WriteProgram();
emergencyProjects.Hour = 19;
emergencyProjects.WriteProgram();
emergencyProjects.Hour = 22;
emergencyProjects.WriteProgram();
Console.Read();
}
//结果表现如下
当前时间:9点 上午工作,精神百倍
当前时间:10点 上午工作,精神百倍
当前时间:12点 饿了,午饭;犯困,午休
当前时间:13点 下午状态还不错,继续努力
当前时间:14点 下午状态还不错,继续努力
当前时间:17点 加班哦,疲累之极
当前时间:19点 加班哦,疲累之极
当前时间:22点 不行了,睡着了
十九.适配器模式
//客户所期待的接口
class Target
{
public virtual void Request()
{
Console.WriteLine("普通请求!");
}
}
//需要适配的类
class Adaptee
{
public void SpecificRequest()
{
Console.WriteLine("特殊请求!")
}
}
//适配(通过在内部包装一个Adaptee对象,把源接口转换成目标接口)
class Adapter : Target
{
private Adaptee adaptee = new Adaptee();
public override void Request()
{
adaptee.SpecificRequest();
}
}
//客户端
static void Main(string[] args)
{
Target target = new Adapter();
target.Request();
Console.Read();
}
二十.备忘录模式
class GameRole
{
//生命力
private int vit;
public int Vitality;
//攻击力
private int atk;
public int Attack;
//防御力
private int def;
public int Defense;
//保存角色状态
public RoleStateMemnto SaveState()
{
return (new RoleStateMemento(vit,atk,def))
}
//恢复角色状态
public void RecoveryState(RoleStateMemento memento)
{
this.vit= memento.Vitality;
this.atk=memento.Attack;
this.def= memento.Defense;
}
}
//角色状态存储箱
class RoleStateMemento
{
private int vit;
private int atk;
private int def;
public RoleStateMemento(int vit,int atk,int def)
{
this.vit = vit;
this.atk = atk;
this.def = def;
}
//生命力
public int Vitality
{
get{return vit;}
set{vit = value;}
}
//攻击力
public int Attack
{
get{return atk;}
set{ack = value;}
}
//防御力
public int Defense
{
get{return def;}
set{def = value;}
}
//角色状态管理类
class RoleStateCaretaker
{
private RoleStateMemento memento;
public RoleStateMemento Memento
{
get{return memento;}
set{memento value;}
}
}
//客户端代码
static void Main(string[] args)
{
//大战Boss前
GameRole lixiaoyao = new GameRole();
lixiaoyao.GetInitState();
lixiaoyao.StateDisplay();
//保存进度
RoleStateCaretaker stateAdmin = new RoleStateCaretaker();
stateAdmin.Memento = lixiaoyao.SaveState();
//大战Boss时,损耗严重
lixiaoyao.Fight();
lixiaoyao.StateDisplay();
//恢复之前状态
lixiaoyao.RecoveryState(stateAdmin.Memento);
lixiaoyao.StateDisplay();
Console.Read();
}
}
二十一.组合模式
将对象组合成树形结构以表示部分-整体的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
用于菜单的分级,树状结构
//Component 为组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component的子部件。
abstract class Component
{
protected string name;
public Component(string name)
{
this.name = name;
}
//通常都用Add和remove方法来提供增加或移除树叶或树枝的功能
public abstract void Add(Component c);
public abstract void Remove(Component c);
public abstract void Display(int depth);
}
//Leaf 在组合中表示叶节点对象,叶节点没有子节点。
class Leaf : Component
{
public Leaf(string name):base(name){}
//由于叶子节点没有再增加分枝和树叶,所有Add 和Remove 方法实现它没有意义,但这样做可以消除叶节点和枝节点对象在抽象层次的区别,它们具备完全一致的接口
public override void Add(Component c)
{
Console.WriteLine("Cannot add to a leaf");
}
public override void Remove(Component c)
{
Console.WriteLine("Cannot remove from a leaf");
}
//叶节点的具体方法,此处是显示其名称和级别
public override void Display(int depth)
{
Console.WriteLine(new string('-',depth)+name);
}
}
//Composite 定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关的操作,比如增加Add 和删除Remove
class Composite : Component
{
private List<Component> children = new List<Component>();
public Composite(string name) : base(name){}
public override void Add(Component c)
{
children.Add(c);
}
public override void Remove(Component c)
{
children.Remove(c);
}
public override void Display(int depth)
{
//显示其枝节点名称,并对其下级进行遍历
Console.WriteLine(new string('-',depth)+name);
foreach (Component component in children)
{
component.Display(depth+2);//递归
}
}
}
//客户端代码,能通过Component 接口操作组合部件的对象
static void Main(string[] args)
{
Composite root = new Composite("root");
root.Add(new Leaf("Leaf A"));
root.Add(new Leaf("Leaf B"));
Composite comp = new Composite("Composite X");
comp.Add(new Leaf("Leaf XA"));
comp.Add(new Leaf("Leaf XB"));
root.Add(comp);
Composite comp2 = new Composite("Composite XY");
comp.Add(new Leaf("Leaf XXA"));
comp.Add(new Leaf("Leaf XXB"));
root.Add(comp2);
root.Add(new Leaf("Leaf C"));
Leaf leaf = new Leaf("Leaf D")
root.Add(leaf);
root.Remove(leaf);
root.Display(1);
Console.Read();
}
//结果
-root
---Leaf A
---Leaf B
---Composite X
-----Leaf XA
-----Leaf XB
-----Composite XY
-------Leaf XYA
-------Leaf XYB
---Leaf C
二十二.迭代器模式
二十三.单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
二十四.桥接模式
实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让他们独立变化,减少他们之间的耦合。
二十五.命令模式
用来声明执行操作的接口
abstract class Command
{
protected Receiver reveiver;
public Command(Receiver receiver)
{
this.receiver = receiver;
}
abstract public void Execute();
}
//将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现Execute。
class ConcreteCommand : Command
{
public ConcreteCommand(Receiver receiver) : base(receiver)
{ }
public override void Execute()
{
receiver.Action();
}
}
//invoker类,要求该命令执行这个请求。
class Invoker
{
private Command command;
public void SetCommand(Command command)
{
this.command = command;
}
public void ExecuteCommand()
{
command.Execute();
}
}
//Receiver类,知道如何实施与执行一个与请求相关的操作,任何类都可能作为一个接口者。
class Receiver
{
public void Action()
{
Console.WriteLine("执行请求!");
}
}
//客户端代码,创建一个具体命令对象并设定它的接收者
static void Main(string[] args)
{
Receiver r = new Receiver();
Command c = new ConcreteCommand(r);
Invoker i = new Invoker();
i.setCommand(c);
i.ExecuteCommand();
Console.Read();
}
二十六.敏捷开发原则
不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般就不要着急去实现他,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。
二十七.职责链模式
//管理者
abstract class Manager
{
protect string name;
//管理者的上级
protect Manager superior;
public Manager(string name)
{
this.name = name;
}
//设置管理者的上级
public void SetSuperior(Manager superior)
{
this.superior = superior;
}
//申请请求
abstract public void RequestApplication(Request request);
}
//经理
class CommonManager : Manager
{
public CommonManager(string name) : base(name){ }
public override void RequestApplication(Request request)
{
if(Request.RequestType == "请假" && request.Number <= 2)
{
Console.WriteLine("{0}:{1} 数量{2} 被批准",name,request.RequestContent,request.Number);
}
else
{
if(superior != null)
superior.RequestApplications(request);
}
}
}
//总监
class Majordomo : Manager
{
public Majordomo(string name) : base(name){ }
public override void RequestApplication(Request request)
{
if(Request.RequestType == "请假" && request.Number <= 5)
{
Console.WriteLine("{0}:{1} 数量{2} 被批准",name,request.RequestContent,request.Number);
}
else
{
if(superior != null)
superior.RequestApplications(request);
}
}
}
//总经理
class GeneralManager : Manager
{
public GeneralManager(string name) : base(name){ }
public override void RequestApplication(Request request)
{
if(Request.RequestType == "请假")
{
Console.WriteLine("{0}:{1} 数量{2} 被批准",name,request.RequestContent,request.Number);
}
else if(Request.RequestType == "加薪" && request.Number <= 500)
{
Console.WriteLine("{0}:{1} 数量{2} 被批准",name,request.RequestContent,request.Number);
}
else if(Request.RequestType == "加薪" && request.Number > 500)
{
Console.WriteLine("{0}:{1} 数量{2} 再说吧",name,request.RequestContent,request.Number);
}
}
}
//客户端代码
static void Main(string[] args)
{
CommonManager jinli = new CommonManager("金利");
Majordomo zongjian = new Majordomo("宗剑");
GeneralManager zhongjianli = new GenerialManager("钟精励");
jinli.SetSuperior(zongjian);
zongjian.SetSuperior(zhongjingli);
Request request = new Request();
request.RequestType = "请假";
request.RequestContent = "小菜请假";
request.Number = 1;
jingli.RequestApplication(request);
Request request2 = new Request();
request.RequestType = "请假";
request.RequestContent = "小菜请假";
request.Number = 4;
jingli.RequestApplication(request2);
Request request3 = new Request();
request.RequestType = "加薪";
request.RequestContent = "小菜请求加薪";
request.Number = 500;
jingli.RequestApplication(request3);
Request request4 = new Request();
request.RequestType = "加薪";
request.RequestContent = "小菜请求加薪";
request.Number = 1000;
jingli.RequestApplication(request4);
Console.Read();
}
//结果
金利:小菜请假 数量1 被批准
宗剑:小菜请假 数量4 被批准
钟精励:小菜请求加薪 数量500 被批准
钟精励:小菜请求加薪 数量1000 再说吧
二十八.中介者模式
优点:Mediator 的出现减少了各个Colleague 的耦合,使得可以独立的改变和复用各个Colleague类和Mediator
缺点:是得Mediator变得非常复杂
二十九.享元模式
优点:可以运用共享技术有效的支持大量细粒度的对象
缺点:使得程序的逻辑复杂化,应当在有足够多的对象实例可供共享时才值得使用共享模式
三十.解释器模式
//演奏内容
class PlayContext
{
//演奏文本
private string text;
public string PlayText;
{
get{return text;}
set{text = value;}
}
}
//表达式类
abstract class Expression
{
//解释器
public void Interpret(PlayContext context)
{
if(context.PlayText.Length==0)
{
return;
}
else
{
string playKey = context.PlayText.Substring(0,1);
context.PlayText = context.PlayText.Substring(2);
double playValue = Convert.ToDouble(context.PlayText.Substring(0,context.PlayText.IndexOf(" ")));
context.PlayText = context.PlayText.Substring(context.PlayText.IndexOf(" ") +1);
Excute(playKey,playValue);
}
}
//执行
public abstract void Excute(string key,double vlaue);
}
//音符类
class Note : Expression
{
public override void Excute(string key,double value)
{
string note = "";
switch(key)
{
case "C":
note = "1";
break;
case "D":
note = "2";
break;
case "E":
note = "3";
break;
case "F":
note = "4";
break;
case "G":
note = "5";
break;
case "A":
note = "6";
break;
case "B":
note = "7";
break;
}
Console.Write("{0} ", note);
}
}
//音阶类
class Scale : Expression
{
public override void Excute(string key,double value)
{
string scale = "";
switch(Convert.ToInt32(vlaue))
{
case 1:
note = "低音";
break;
case 2:
note = "中音";
break;
case 3:
note = "高音";
break;
}
Console.Write("{0} ", note);
}
}
//客户端代码
static void Main(string[] args)
{
PlayContext context = new PlayContext();
console.WriteLine("上海滩: ");
context.PlayText = " O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3 ";
Expression expression = null;
try
{
while (context.PlayText.Length > 0)
{
string str = context.PlayText.Substring(0,1);
switch (str)
{
case "O":
expression = new Scale();
break;
case "C":
case "D":
case "E":
case "F":
case "G":
case "A":
case "B":
case "P":
expression = new Note();
break;
}
expression.Interpret(context);
}
}
catch(Exception ex)
{
Console.WreteLine(ex.Message);
}
Console.Read();
}
//结果
上海滩:
中音 356352356 高音 1 中音 65132
三十一.访问者模式
创建型模式
隐藏了这些类的实例是如何被创建和放在一起,整个系统关于这些对象所知道的是由抽象类定义的接口。这样,创建型模式在创建了什么、谁创建它、他是怎么被创建的,以及何时创建这些方面提供了很大的灵活性。
结构型模式
行为型模式
最后
以上就是友好电话为你收集整理的大话设计模式的全部内容,希望文章能够帮你解决大话设计模式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复