Head First 设计模式 (Eric Freeman / Elisabeth Freeman / Kathy Sierra / Bert Bates 著)
1. 欢迎来到设计模式世界:设计模式入门 (已看)
策略模式
定义了算法族,分别分装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户.
设计原则
找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起
针对接口编程,而不是针对实现编程
多用组合,少用继承
using System; namespace Test1 { class Program { static void Main(string[] args) { Duck duck = new MallardDark(); duck.performQuack(); duck.performFly(); Duck model = new ModelDuck(); model.performFly(); model.setFlyBehavior(new FlyRocketPowered()); model.performFly(); } } } public interface IFlyBehavior { void fly(); } public class FlyWithWings : IFlyBehavior { public void fly() { Console.WriteLine("I'm flying!"); } } public class FlyNoWay : IFlyBehavior { public void fly() { Console.WriteLine("I can't fly"); } } public class FlyRocketPowered : IFlyBehavior { public void fly() { Console.WriteLine("I'm flying with a rocket"); } } public interface IQuackBehavior { void quack(); } public class Quack : IQuackBehavior { public void quack() { Console.WriteLine("Quack"); } } public class MuteQuack : IQuackBehavior { public void quack() { Console.WriteLine("<< Silence >>"); } } public class Squeak : IQuackBehavior { public void quack() { Console.WriteLine("Squeak"); } } public abstract class Duck { protected IFlyBehavior flyBehavior; protected IQuackBehavior quackBehavior; public Duck() { } public abstract void display(); public void setFlyBehavior(IFlyBehavior fb) { flyBehavior = fb; } public void setQuackBehavior(IQuackBehavior qb) { quackBehavior = qb; } public void performFly() { flyBehavior.fly(); } public void performQuack() { quackBehavior.quack(); } public void swim() { Console.WriteLine("All ducks float,even decoys!"); } } public class MallardDark : Duck { public MallardDark() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } public override void display() { Console.WriteLine("I'm a real Mallard duck"); } } public class ModelDuck : Duck { public ModelDuck() { flyBehavior = new FlyNoWay(); quackBehavior = new Quack(); } public override void display() { Console.WriteLine("I'm a model duck"); } }
2. 让你的对象知悉现况:观察者模式 (已看)
观察者模式
定义了对象之间的一对多依赖,这样依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新.
设计原则
为了交互对象之间的松耦合设计而努力
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace ConsoleApplication1 { public class Program { public static void Main(string[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(80,65,30.4f); } } public interface ISubject { void registerObserver(IObserver o); void removeObserver(IObserver o); void notifyObserver(); } public class WeatherData : ISubject { private List<IObserver> observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new List<IObserver>(); } public void registerObserver(IObserver o) { observers.Add(o); } public void removeObserver(IObserver o) { observers.Remove(o); } public void notifyObserver() { foreach (var observer in observers) { observer.update(temperature,humidity,pressure); } } public void measurementsChanged() { notifyObserver(); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } } public interface IObserver { void update(float temp, float humidity, float pressure); } public interface IDisplayElement { void display(); } public class CurrentConditionsDisplay : IObserver, IDisplayElement { private float temperature; private float humidity; private ISubject weatherData; public CurrentConditionsDisplay(ISubject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; display(); } public void display() { Console.WriteLine("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity"); } } }
3. 装饰对象:装饰者模式 (已看)
装饰者模式
动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的代替方案
设计原则
类应该对扩展开发,对修改关闭
using System; namespace Test1 { class Program { static void Main(string[] args) { ABeverage beverage = new Espresso(); Console.WriteLine(beverage.getDescription() + " $" + beverage.cost()); ABeverage beverage2 = new HouseBlend(); beverage2 = new Mocha(beverage2); Console.WriteLine(beverage2.getDescription() + " $" + beverage2.cost()); } } public abstract class ABeverage { protected string description = "Unknown Beverage"; public virtual string getDescription() { return description; } public abstract double cost(); } public class Espresso : ABeverage { public Espresso() { description = "Espresso"; } public override double cost() { return 1.99; } } public class HouseBlend : ABeverage { public HouseBlend() { description = "House Blend Coffee"; } public override double cost() { return 0.89; } } public abstract class ACondimentDecorator : ABeverage { public abstract override string getDescription(); } public class Mocha : ACondimentDecorator { private ABeverage beverage; public Mocha(ABeverage beverage) { this.beverage = beverage; } public override string getDescription() { return beverage.getDescription() + ", Mocha"; } public override double cost() { return 0.20 + beverage.cost(); } } }
4. 烘烤OO的精华:工厂模式 (已看)
在设计模式中,所谓的"实现一个接口"并"不一定"表示"写一个类,并利用:来实现某个C#接口"."实现一个接口"泛指"实现某个超类型(可以是类或接口)的某个方法"
工厂方法模式
定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个.工厂方法让类把实例化推迟到子类
设计原则
要依赖抽象,不要依赖具体类
using System; using System.Collections; using System.Runtime.InteropServices; namespace Test1 { class Program { static void Main(string[] args) { APizzaStore nyStore = new NYPizzaStore(); APizzaStore chicagoStore = new ChicagoStylePizzaStore(); APizza pizza = nyStore.orderPizza("cheese"); Console.WriteLine("Ethan ordered a " + pizza.getName() + "\n"); pizza = chicagoStore.orderPizza("cheese"); Console.WriteLine("Joel ordered a " + pizza.getName() + "\n"); } } public abstract class APizzaStore { public APizza orderPizza(string type) { APizza pizza; pizza = createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } public abstract APizza createPizza(string type); } public class NYPizzaStore : APizzaStore { public override APizza createPizza(string item) { if (item.Equals("cheese")) { return new NYStyleCheesePizza(); } else { return null; } } } public class ChicagoStylePizzaStore : APizzaStore { public override APizza createPizza(string item) { if (item.Equals("cheese")) { return new ChicagoStyleCheesePizza(); } else { return null; } } } public abstract class APizza { protected string name; protected string dough; protected string sauce; protected ArrayList toppings = new ArrayList(); public virtual void prepare() { Console.WriteLine("Preparing " + name); Console.WriteLine("Tossing dough..."); Console.WriteLine("Adding sauce..."); Console.WriteLine("Adding toppings: "); for (int i = 0; i < toppings.Count; i++) { Console.WriteLine(" " + toppings[i]); } } public virtual void bake() { Console.WriteLine("Bake for 25 minutes at 350"); } public virtual void cut() { Console.WriteLine("Cutting the pizza into diagonal slices"); } public virtual void box() { Console.WriteLine("Place pizza in official PizzaStore box"); } public string getName() { return name; } } public class NYStyleCheesePizza : APizza { public NYStyleCheesePizza() { name = "NY Style Sauce and Cheese Pizza"; dough = "Thin Crust Dough"; sauce = "Marinara Sauce"; toppings.Add("Grated Reggiano Cheese"); } } public class ChicagoStyleCheesePizza : APizza { public ChicagoStyleCheesePizza() { name = "Chicago Style Deep Dish Cheese Pizza"; dough = "Extra Thick Crust Dough"; sauce = "Plum Tomato Sauce"; toppings.Add("Shredded Mozzarella Cheese"); } public override void cut() { Console.WriteLine("Cutting the pizza into square slices"); } } }
抽象工厂模式
提供一个接口,用于创建相关或依赖对象的家族.而不需要明确指定具体类
5. 独一无二的对象:单件模式 (已看)
单件模式
确保一个类只有一个实例,并提供全局访问点.
public class Singleton { private volatile static Singleton uniqueInstance; private static readonly object syncRoot = new object(); private Singleton() { } public static Singleton getInstance() { if (uniqueInstance == null) { lock (syncRoot) { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } } return uniqueInstance; } }
6. 封装调用:命令模式 (已看)
命令模式
将请求封装成对象.这可以让你使用不同的请求,队列.或者日志请求来参数化其他对象.命令模式也可以支持撤销操作.
7. 随遇而安:适配器与外观模式 (已看)
适配器模式
将一个类的接口,转换成客户期望的另一个接口.适配器让原本接口不兼容的类可以合作无间
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace ConsoleApplication1 { public class Program { public static void Main(string[] args) { IDuck duck = new MallardDuck(); ITurkey turkey = new WildTurkey(); IDuck turkeyAdapter = new TurkeyAdapter(turkey); Console.WriteLine("The Turkey says..."); turkey.gobble(); turkey.fly(); Console.WriteLine("\nThe Duck says..."); testDuck(duck); Console.WriteLine("\nThe TurkeyAdapter says..."); testDuck(turkeyAdapter); } static void testDuck(IDuck duck) { duck.quack(); duck.fly(); } } public interface IDuck { void quack(); void fly(); } public class MallardDuck : IDuck { public void quack() { Console.WriteLine("Quack"); } public void fly() { Console.WriteLine("I'm flying."); } } public interface ITurkey { void gobble(); void fly(); } public class WildTurkey : ITurkey { public void gobble() { Console.WriteLine("Gobble gobble"); } public void fly() { Console.WriteLine("I'm flying a short distance."); } } public class TurkeyAdapter : IDuck { private ITurkey turkey; public TurkeyAdapter(ITurkey turkey) { this.turkey = turkey; } public void quack() { turkey.gobble(); } public void fly() { for (int i = 0; i < 5; i++) { turkey.fly(); } } } }
外观模式
提供了一个统一的接口,用来访问子系统中的一群接口.外观定义了一个高层接口,让子系统更容易使用.
设计原则
最少知识原则:只和你的密友谈话.
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace ConsoleApplication1 { public class Program { public static void Main(string[] args) { Screen screen = new Screen(); CdPlayer cdPlayer = new CdPlayer(); HomeTheaterFacade homeTheater = new HomeTheaterFacade(screen,cdPlayer); homeTheater.watchMove(); } } public class Screen { public void Open() { Console.WriteLine("Screen Open"); } } public class CdPlayer { public void Play() { Console.WriteLine("CdPlayer Play"); } } public class HomeTheaterFacade { private Screen screen; private CdPlayer cdPlayer; public HomeTheaterFacade(Screen screen,CdPlayer cdPlayer) { this.screen = screen; this.cdPlayer = cdPlayer; } public void watchMove() { this.screen.Open(); this.cdPlayer.Play(); } } }
8. 封装算法:模板方法模式 (已看)
模板方法模式
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤
"好莱坞原则"
别调用(打电话给)我们,我们会调用(打电话给)你.
好莱坞原则可以给我们一种防止"依赖腐败"的方法.当高层组件依赖低层组件,而低层组件又依赖高层组件,
而高层组件又依赖边侧组件,而边侧组件又依赖低层组件时,依赖腐败就发生了.在这种情况下,没有人可以轻易地搞懂系统是如何设计的.
在好莱坞原则下,我们允许低层组件将自己挂钩到系统上,但是高层组件会决定什么时候和怎样使用这些低层组件.
换句话说,高层组件对待低层组件的方式是"别调用我们,我们会调用你".
using System; using System.Collections; using System.IO.Pipes; using System.Runtime.InteropServices; using System.Text; namespace Test1 { class Program { static void Main(string[] args) { ACaffeineBeverage tea = new Tea(); tea.prepareRecipe(); ACaffeineBeverage coffee = new Coffee(); coffee.prepareRecipe(); } } public abstract class ACaffeineBeverage { public void prepareRecipe() { boilWater(); brew(); pourInCup(); addCondiments(); } public abstract void brew(); public abstract void addCondiments(); public void boilWater() { Console.WriteLine("Boiling water"); } public void pourInCup() { Console.WriteLine("Pouring into cup"); } } public class Tea : ACaffeineBeverage { public override void brew() { Console.WriteLine("Steeping the tea"); } public override void addCondiments() { Console.WriteLine("Adding Lemon"); } } public class Coffee : ACaffeineBeverage { public override void brew() { Console.WriteLine("Dripping Coffee through filter"); } public override void addCondiments() { Console.WriteLine("Adding Sugar and Milk"); } } }
9. 管理良好的集合:迭代器与组合模式 (已看)
迭代器模式
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示.
设计原则
一个类应该只有一个引起变化的原因
听起来很容易,但其实做起来并不简单:区分设计中的责任,是最困难的事情之一.我们的大脑很习惯看着一大群的行为,
然后将它们集中在一起,尽管他们可能属于两个或多个不同的责任.想要成功的唯一方法,就是努力不懈地检查你的设计,
随着系统的成长,随时观察有没有迹象显示某个类改变的原因超出一个.
内聚(cohesion)用来度量一个类或模块紧密地达到单一目的或责任.
当一个模块或一个类被设计成只支持一组相关的功能时,反之,当被设计成支持一组不相关的功能时,我们说它具有低内聚
内聚是一个比单一责任原则更普遍的概念,但两者其实关系是很密切的.遵守这个原则的类容易具有很高的凝聚力,而且比背负许多责任的低内聚类更容易维护
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Reflection.Metadata.Ecma335; namespace Test1 { class Program { static void Main(string[] args) { printMenu(); } static void printMenu() { PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu(); DinerMenu dinerMenu = new DinerMenu(); Waitress waitress = new Waitress(pancakeHouseMenu,dinerMenu); waitress.printMenu(); } } public class MenuItem { private string name; private string description; private bool vegetarian; private double price; public MenuItem(string name, string description, bool vegetarian, double price) { this.name = name; this.description = description; this.vegetarian = vegetarian; this.price = price; } public string getName() { return name; } public string getDescription() { return description; } public double getPrice() { return price; } public bool isVegetarian() { return vegetarian; } } public class PancakeHouseMenu { private ArrayList menuItems; public PancakeHouseMenu() { menuItems = new ArrayList(); addItem("K&B's Pancake Breakfast","Pancakes with scrambled eggs,and toast",true,2.99); addItem("Regular Pancake Breakfast","Pancakes with fried eggs,sausage",false,2.99); addItem("Blueberry Pancakes","Pancakes made with fresh blueberries",true,3.49); addItem("Waffles","Waffles, with your choice of blueberries or starwberries",true,3.59); } public void addItem(string name, string description, bool vegetarian, double price) { MenuItem menuItem = new MenuItem(name,description,vegetarian,price); menuItems.Add(menuItem); } public Iterator createIterator() { return new PancakeHouseIterator(menuItems); } } public class DinerMenu { private int MAX_ITEMS = 6; private int numberOfItems = 0; private MenuItem[] menuItems; public DinerMenu() { menuItems = new MenuItem[MAX_ITEMS]; addItem("K&B's Pancake Breakfast","Pancakes with scrambled eggs,and toast",true,2.99); addItem("Regular Pancake Breakfast","Pancakes with fried eggs,sausage",false,2.99); addItem("Blueberry Pancakes","Pancakes made with fresh blueberries",true,3.49); addItem("Waffles","Waffles, with your choice of blueberries or starwberries",true,3.59); } public void addItem(string name, string description, bool vegetarian, double price) { MenuItem menuItem = new MenuItem(name,description,vegetarian,price); if (numberOfItems >= MAX_ITEMS) { Console.WriteLine("Sorry,menu is full! Can't add item "); } else { menuItems[numberOfItems] = menuItem; numberOfItems = numberOfItems + 1; } } public Iterator createIterator() { return new DinerMenuIterator(menuItems); } } public interface Iterator { bool hasNext(); object next(); } public class DinerMenuIterator : Iterator { private MenuItem[] items; private int position = 0; public DinerMenuIterator(MenuItem[] items) { this.items = items; } public object next() { MenuItem menuItem = items[position]; position++; return menuItem; } public bool hasNext() { if (position >= items.Length || items[position] == null) { return false; } else { return true; } } } public class PancakeHouseIterator : Iterator { private ArrayList items; private int position = 0; public PancakeHouseIterator(ArrayList items) { this.items = items; } public object next() { MenuItem menuItem = items[position] as MenuItem; position++; return menuItem; } public bool hasNext() { if (position >= items.Count || items[position] == null) { return false; } else { return true; } } } public class Waitress { private PancakeHouseMenu pancakeHouseMenu; private DinerMenu dinerMenu; public Waitress(PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu) { this.pancakeHouseMenu = pancakeHouseMenu; this.dinerMenu = dinerMenu; } public void printMenu() { Iterator pancakeIterator = pancakeHouseMenu.createIterator(); Iterator dinerIterator = dinerMenu.createIterator(); Console.WriteLine("MENU\n----\nBREAKFAST"); printMenu(pancakeIterator); Console.WriteLine("\nLUNCH"); printMenu(dinerIterator); } private void printMenu(Iterator iterator) { while (iterator.hasNext()) { MenuItem menuItem = iterator.next() as MenuItem; Console.WriteLine(menuItem.getName() + ", "); Console.WriteLine(menuItem.getPrice() + " -- "); Console.WriteLine(menuItem.getDescription()); } } } }
组合模式
允许你将对象组合成树形结构来表现"整体/部分"层次结构.组合能让客户以一致的方式处理个别对象以及对象组合
10. 事物的状态:状态模式 (已看)
状态模式
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类
using System; using System.Collections; using System.Net; using System.Runtime.InteropServices.ComTypes; namespace Test1 { class Program { static void Main(string[] args) { GumballMachine gumballMachine = new GumballMachine(5); gumballMachine.insertQuarter(); gumballMachine.turnCrank(); gumballMachine.insertQuarter(); gumballMachine.ejectQuarter(); gumballMachine.turnCrank(); gumballMachine.insertQuarter(); gumballMachine.turnCrank(); gumballMachine.insertQuarter(); gumballMachine.turnCrank(); gumballMachine.ejectQuarter(); } } public interface IState { void insertQuarter(); void ejectQuarter(); void turnCrank(); void dispense(); } public class SoldOutState : IState { private GumballMachine gumballMachine; public SoldOutState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } public void insertQuarter() { Console.WriteLine("You can't insert a quarter,the machine is sold out"); } public void ejectQuarter() { Console.WriteLine("You can't eject,you haven't inserted a quarter yet"); } public void turnCrank() { Console.WriteLine("You turned,but there are no gumballs"); } public void dispense() { Console.WriteLine("No gumball dispensed"); } } public class NoQuarterState : IState { private GumballMachine gumballMachine; public NoQuarterState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } public void insertQuarter() { Console.WriteLine("You inserted a quarter"); gumballMachine.setState(gumballMachine.getHasQuarterState()); } public void ejectQuarter() { Console.WriteLine("You haven't inserted a quarter"); } public void turnCrank() { Console.WriteLine("You turned,but there's no quarter"); } public void dispense() { Console.WriteLine("You need to pay first"); } } public class HasQuarterState : IState { private GumballMachine gumballMachine; public HasQuarterState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } public void insertQuarter() { Console.WriteLine("You can't insert another quarter"); } public void ejectQuarter() { Console.WriteLine("Quarter returned"); gumballMachine.setState(gumballMachine.getNoQuarterState()); } public void turnCrank() { Console.WriteLine("You turned..."); gumballMachine.setState(gumballMachine.getSoldState()); } public void dispense() { Console.WriteLine("No gumball dispensed"); } } public class SoldState : IState { private GumballMachine gumballMachine; public SoldState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } public void insertQuarter() { Console.WriteLine("Please wait,we're already giving you a gumball"); } public void ejectQuarter() { Console.WriteLine("Sorry, you already turned the crank"); } public void turnCrank() { Console.WriteLine("Turning twice doesn't get you another gumball!"); } public void dispense() { gumballMachine.releaseBall(); if (gumballMachine.getCount() > 0) { gumballMachine.setState(gumballMachine.getNoQuarterState()); } else { Console.WriteLine("Oops,out of gumballs!"); gumballMachine.setState(gumballMachine.getHasQuarterState()); } } } public class GumballMachine { private IState soldOutState; private IState noQuarterState; private IState hasQuarterState; private IState soldState; private IState state; private int count = 0; public GumballMachine(int numberGumballs) { soldOutState = new SoldOutState(this); noQuarterState = new NoQuarterState(this); hasQuarterState = new HasQuarterState(this); soldState = new SoldState(this); state = soldOutState; this.count = numberGumballs; if (numberGumballs > 0) { state = noQuarterState; } } public void insertQuarter() { state.insertQuarter(); } public void ejectQuarter() { state.ejectQuarter(); } public void turnCrank() { state.turnCrank(); state.dispense(); } public IState getState() { return state; } public void setState(IState state) { this.state = state; } public void releaseBall() { Console.WriteLine("A gumball comes rolling out the slot..."); if (count != 0) { count = count - 1; } } public int getCount() { return count; } public IState getSoldOutState() { return soldOutState; } public IState getNoQuarterState() { return noQuarterState; } public IState getHasQuarterState() { return hasQuarterState; } public IState getSoldState() { return soldState; } } }
11. 控制对象访问: 代理模式 (已看)
代理模式
为另一个对象提供一个替身或占位符以控制对这个对象的访问
12. 模式中的模式: 复合模式 (已看)
13. 真实世界中的模式: 与设计模式相处 (已看)
定义设计模式
模式是在某情境(context)下,针对某问题的某种解决方案
情境就是应用某个模式的情况.这应该是会不断出现的情况
问题就是你想在某情境下达到的目标,但也可以是某情境下的约束
解决方案就是你所追求的:一个通用的设计,·用来解决约束,达到目标
创建型
创建型模式涉及到将对象实例化,这类模式都提供一个方法,将客户从所需要实例化的对象中解耦.
Singleton
Abstract Factory
Factory Method
Prototype
Builder
结构型
结构型模式可以让你把类或对象组合到更大的结构中.
Decorator
Composite
Adapter
Proxy
Facade
Flyweight
Bridge
行为型
只要是行为型模式,都涉及到类和对象如何交互及分配职责
Template Method
Command
Iterator
Observer
State
Strategy
Interpreter
Chain of Responsibility
Visitor
Mediator
Memento
14. 附录A:剩下的模式