├── ch3-decoration ├── IO │ ├── test.txt │ ├── InputTest.java │ └── LowerCaseInputStream.java ├── Beverge │ ├── CondimentDecorator.java │ ├── DarkRoast.java │ ├── HouseBlend.java │ ├── Espresso.java │ ├── Beverage.java │ ├── Mocha.java │ ├── Soy.java │ ├── Whip.java │ └── StarbuzzCoffee.java └── README.md ├── ch6-command ├── Command.java ├── NoCommand.java ├── Light.java ├── README.md ├── SimpleRemoteControl.java ├── LightOnCommand.java ├── LightOffCommand.java ├── RemoteControlTest.java └── RemoteControl.java ├── ch7-adapter ├── IDuck.java ├── Turkey.java ├── WildTurkey.java ├── MallardDuckImpl.java ├── DuckTestDrive.java ├── TurkeyAdapterImpl.java └── README.md ├── ch1-interface ├── IFlyBehavior.java ├── IQuackBehavior.java ├── FlyNoWay.java ├── Quack.java ├── QuackMute.java ├── FlyWithWings.java ├── FlyWithRocket.java ├── ModelDuck.java ├── MallardDuck.java ├── README.md ├── Test.java └── Duck.java ├── ch2-observer ├── DisplayElement.java ├── Observable │ ├── DisplayElement.java │ ├── WeatherStation.java │ ├── WeatherData.java │ └── CurrentConditionDisplay.java ├── Observer.java ├── Subject.java ├── WeatherStation.java ├── README.md ├── CurrentConditionDisplay.java └── WeatherData.java ├── .gitignore ├── ch4-factory ├── Pizza.java ├── CheesePizza.java ├── Pepperoni.java ├── SimplePizzaFactory.java ├── PizzaStore.java └── README.md ├── ch8-template-method ├── TemplateMethodTest.java ├── TeaCaffeineBeverageImpl.java ├── CoffeeCaffeineBeverageImpl.java ├── Tea.java ├── Coffee.java ├── CaffeineBeverage.java └── README.md ├── ch5-singleton ├── SingletonEagerly.java ├── SingletonLazy.java ├── ChocolateBoiler.java ├── SingletonDoubleCheckedLocking.java ├── ChocolateBoilerSingleton.java └── README.md └── README.md /ch3-decoration/IO/test.txt: -------------------------------------------------------------------------------- 1 | Hello World! -------------------------------------------------------------------------------- /ch6-command/Command.java: -------------------------------------------------------------------------------- 1 | public interface Command { 2 | public void execute(); 3 | } 4 | -------------------------------------------------------------------------------- /ch7-adapter/IDuck.java: -------------------------------------------------------------------------------- 1 | public interface IDuck { 2 | public void quack(); 3 | public void fly(); 4 | } 5 | -------------------------------------------------------------------------------- /ch7-adapter/Turkey.java: -------------------------------------------------------------------------------- 1 | public interface Turkey { 2 | public void gobble(); 3 | public void fly(); 4 | } 5 | -------------------------------------------------------------------------------- /ch1-interface/IFlyBehavior.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 飞行行为接口类 3 | */ 4 | public interface IFlyBehavior{ 5 | public void fly(); 6 | } -------------------------------------------------------------------------------- /ch2-observer/DisplayElement.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 显示元素接口 3 | */ 4 | public interface DisplayElement { 5 | public void display(); 6 | } 7 | -------------------------------------------------------------------------------- /ch1-interface/IQuackBehavior.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * 叫行为接口类 5 | */ 6 | public interface IQuackBehavior{ 7 | public void quack(); 8 | } -------------------------------------------------------------------------------- /ch2-observer/Observable/DisplayElement.java: -------------------------------------------------------------------------------- 1 | package Observable; 2 | 3 | public interface DisplayElement { 4 | public void display(); 5 | } 6 | -------------------------------------------------------------------------------- /ch6-command/NoCommand.java: -------------------------------------------------------------------------------- 1 | public class NoCommand implements Command { 2 | @Override 3 | public void execute() { 4 | 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ch2-observer/Observer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 观察者接口 3 | */ 4 | public interface Observer { 5 | public void update(float temp,float humidity,float pressure); 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .idea 3 | DesignPattern.iml 4 | 将删除 .gitignore 5 | 将删除 .idea/ 6 | 将删除 DesignPattern.iml 7 | out 8 | 9 | -------------------------------------------------------------------------------- /ch4-factory/Pizza.java: -------------------------------------------------------------------------------- 1 | public interface Pizza { 2 | public void prepare(); 3 | public void bake(); 4 | public void cut(); 5 | public void box(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /ch1-interface/FlyNoWay.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 这是飞行行为的实现,给不会飞的鸭子用 3 | */ 4 | public class FlyNoWay implements IFlyBehavior { 5 | @Override 6 | public void fly() { 7 | System.out.println("I can't fly!"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ch1-interface/Quack.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 叫的实现,给会呱呱叫的鸭子用 3 | */ 4 | public class Quack implements IQuackBehavior { 5 | @Override 6 | public void quack() { 7 | System.out.println("Quack,gua gua gua!"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ch2-observer/Subject.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 主题接口 3 | */ 4 | public interface Subject { 5 | public void registerObserver(Observer o); 6 | public void removeObserver(Observer o); 7 | public void notifyObservers(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /ch1-interface/QuackMute.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 鸭子叫的沉默实现,给不会叫的鸭子用 3 | */ 4 | public class QuackMute implements IQuackBehavior { 5 | @Override 6 | public void quack() { 7 | System.out.println("<>"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ch1-interface/FlyWithWings.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 这是飞行行为的实现,给真会飞的鸭子用 3 | */ 4 | public class FlyWithWings implements IFlyBehavior { 5 | @Override 6 | public void fly() { 7 | System.out.println("fly with wings"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ch1-interface/FlyWithRocket.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 火箭动力的飞行行为 3 | */ 4 | public class FlyWithRocket implements IFlyBehavior { 5 | @Override 6 | public void fly() { 7 | System.out.println("I'm flying with a rocket!"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ch1-interface/ModelDuck.java: -------------------------------------------------------------------------------- 1 | public class ModelDuck extends Duck { 2 | public ModelDuck(){ 3 | flyBehavior=new FlyNoWay();//一开始,模型鸭不会飞 4 | quackBehavior=new Quack();//一开始,模型鸭会呱呱叫 5 | } 6 | @Override 7 | public void display() { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ch8-template-method/TemplateMethodTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 模板方法模式测试 3 | */ 4 | public class TemplateMethodTest { 5 | 6 | public static void main(String[] args){ 7 | //new一个茶对象 8 | TeaCaffeineBeverageImpl tea=new TeaCaffeineBeverageImpl(); 9 | tea.prepareRecipe(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch7-adapter/WildTurkey.java: -------------------------------------------------------------------------------- 1 | public class WildTurkey implements Turkey { 2 | @Override 3 | public void gobble() { 4 | System.out.println("Bobble gobble"); 5 | } 6 | 7 | @Override 8 | public void fly() { 9 | System.out.println("I'm flying a short distance"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch7-adapter/MallardDuckImpl.java: -------------------------------------------------------------------------------- 1 | public class MallardDuckImpl implements IDuck { 2 | @Override 3 | public void quack() { 4 | System.out.println("gua!gua!gua!"); 5 | } 6 | 7 | @Override 8 | public void fly() { 9 | System.out.println("I'm flying a long distance"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch2-observer/WeatherStation.java: -------------------------------------------------------------------------------- 1 | public class WeatherStation { 2 | public static void main(String[] args){ 3 | WeatherData weatherData=new WeatherData(); 4 | 5 | CurrentConditionDisplay currentConditionDisplay=new CurrentConditionDisplay(weatherData); 6 | weatherData.setMeasurements(80,65,30.4f); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /ch6-command/Light.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 电灯类 3 | */ 4 | public class Light { 5 | /** 6 | * 开电灯 7 | */ 8 | public void on(){ 9 | System.out.println("light on!"); 10 | } 11 | 12 | /** 13 | * 关电灯 14 | */ 15 | public void off(){ 16 | System.out.println("light off!"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ch3-decoration/Beverge/CondimentDecorator.java: -------------------------------------------------------------------------------- 1 | package Beverge; 2 | 3 | /** 4 | * 调味料装饰者 5 | * Created by jimersylee on 17-8-19. 6 | */ 7 | public abstract class CondimentDecorator extends Beverage { 8 | 9 | /** 10 | * 所有的调料装饰者必须重新实现getDescription方法 11 | * @return 12 | */ 13 | public abstract String getDescription(); 14 | } 15 | -------------------------------------------------------------------------------- /ch4-factory/CheesePizza.java: -------------------------------------------------------------------------------- 1 | public class CheesePizza implements Pizza { 2 | @Override 3 | public void prepare() { 4 | 5 | } 6 | 7 | @Override 8 | public void bake() { 9 | 10 | } 11 | 12 | @Override 13 | public void cut() { 14 | 15 | } 16 | 17 | @Override 18 | public void box() { 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch4-factory/Pepperoni.java: -------------------------------------------------------------------------------- 1 | public class Pepperoni implements Pizza { 2 | @Override 3 | public void prepare() { 4 | 5 | } 6 | 7 | @Override 8 | public void bake() { 9 | 10 | } 11 | 12 | @Override 13 | public void cut() { 14 | 15 | } 16 | 17 | @Override 18 | public void box() { 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch6-command/README.md: -------------------------------------------------------------------------------- 1 | #命令模式 2 | 3 | - 命令模式将发出请求的对象和执行请求的对象解耦 4 | - 在被解耦的两者之间是通过命令对象进行沟通的.命令对象封装了接收者和一个或者一组动作 5 | - 调用者通过调用命令封装execute()发出请求,这会使得接收者的动作被调用 6 | - 调用者可以接受命令当做参数,甚至在运行时动态地进行 7 | - 命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态 8 | - 宏命令是命令的一种简单的延伸,允许调用多个命令.宏方法也可以支持注销 9 | - 实际操作时,很常见使用"聪明"命令对象,也就是直接实现了请求,而不是将工作委托给接收者 10 | - 命令也可以用来实现日志和事务系统 11 | -------------------------------------------------------------------------------- /ch3-decoration/Beverge/DarkRoast.java: -------------------------------------------------------------------------------- 1 | package Beverge; 2 | 3 | /** 4 | * 深度烘焙咖啡 5 | * Created by jimersylee on 17-8-19. 6 | */ 7 | public class DarkRoast extends Beverage { 8 | 9 | public String getDescription(){ 10 | return "DarkRoast"; 11 | } 12 | @Override 13 | public double cost() { 14 | return 1.2; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ch3-decoration/Beverge/HouseBlend.java: -------------------------------------------------------------------------------- 1 | package Beverge; 2 | 3 | /** 4 | * 普通的HouseBlend咖啡 5 | * Created by jimersylee on 17-8-19. 6 | */ 7 | public class HouseBlend extends Beverage { 8 | public HouseBlend() { 9 | description="House Blend Coffee"; 10 | } 11 | 12 | @Override 13 | public double cost() { 14 | return 0.89; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ch3-decoration/Beverge/Espresso.java: -------------------------------------------------------------------------------- 1 | package Beverge; 2 | 3 | /** 4 | * 具体的浓缩咖啡 5 | * Created by jimersylee on 17-8-19. 6 | */ 7 | public class Espresso extends Beverage { 8 | 9 | public Espresso() { 10 | description="Espresso";//description变量继承自Beverage 11 | } 12 | 13 | @Override 14 | public double cost() { 15 | return 1.99; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ch2-observer/Observable/WeatherStation.java: -------------------------------------------------------------------------------- 1 | package Observable; 2 | 3 | public class WeatherStation { 4 | public static void main(String[] args){ 5 | WeatherData weatherData=new WeatherData(); 6 | 7 | CurrentConditionDisplay currentConditionDisplay=new CurrentConditionDisplay(weatherData); 8 | 9 | weatherData.setMeasurements(80,30,33.2f); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch1-interface/MallardDuck.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 绿头鸭类 3 | */ 4 | public class MallardDuck extends Duck { 5 | public MallardDuck(){ 6 | quackBehavior=new Quack();//绿头鸭使用Quack类处理叫,所以当performQuack()被调用时,叫的职责被委托给Quack 7 | flyBehavior=new FlyWithWings();//同理 8 | } 9 | 10 | public void display(){ 11 | System.out.println("I'm a real Mallard duck"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ch1-interface/README.md: -------------------------------------------------------------------------------- 1 | ##软件开发的一个不变真理 2 | 不变的就是变化 3 | 4 | 5 | 驱动改变的因素很多.找出你的应用中需要改变代码的原因 6 | 1. 用户需要新的功能 7 | 1. 需要推出新的活动 8 | 1. 应用改版 9 | 1. 为了更好的性能 10 | 11 | 12 | 继承不能很好的解决问题,因为对象的行为在子类里不断地改变,并且让所有子类都有这些行为是不恰当的. 13 | 使用Fooable等接口,只用能实现的类才继承Fooable接口,但是java接口不具有实现代码,所以继承接口无法达到代码的复用. 14 | 15 | 引出一个**设计原则** 16 | >找出应用中可能需要变化之处,把它独立出来,不要和那些不需要变化的代码混在一起 17 | 18 | 19 | **设计原则** 20 | >针对接口编程,而不是针对实现编程 21 | 22 | 23 | -------------------------------------------------------------------------------- /ch2-observer/README.md: -------------------------------------------------------------------------------- 1 | ###观察者模式(Observer) 2 | 让你的对象知悉现况 3 | 4 | 使用自定义的Subject(主题)与Observer(观察者模式) 5 | 6 | 7 | 设计原则 8 | >找出程序中会变化的方面,然后将其和固定不变的部分分离 9 | 10 | 在观察者模式中,会改变的事主题的状态,以及观察者的数目和类型.用这个模式,你可以改变依赖于主题状态的对象,却不改变主题.这就叫提前规划 11 | 12 | >针对接口编程,不针对实现编程 13 | 14 | 主题与观察者都使用接口:观察者利用主题的接口向主题注册,二主题利用观察者接口通知观察者.这样可以让两者之前运作正常,同时具有松耦合的优点 15 | >多用组合,少用继承 16 | 17 | 观察者模式利用"组合"将许多观察者组合进主题中.对象之前的这种关系不是通过继承产生的,而是在运行时利用组合的方式而产生的. -------------------------------------------------------------------------------- /ch3-decoration/Beverge/Beverage.java: -------------------------------------------------------------------------------- 1 | package Beverge; 2 | 3 | /** 4 | * 饮料抽象类 5 | * Created by jimersylee on 17-8-19. 6 | */ 7 | public abstract class Beverage { 8 | String description="Unknown Beverage"; 9 | 10 | public String getDescription(){ 11 | return description; 12 | } 13 | 14 | /** 15 | * 子类必须继承此计算价格的方法 16 | * @return 17 | */ 18 | public abstract double cost(); 19 | } 20 | -------------------------------------------------------------------------------- /ch8-template-method/TeaCaffeineBeverageImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 继承自咖啡因饮料 3 | */ 4 | public class TeaCaffeineBeverageImpl extends CaffeineBeverage { 5 | 6 | /** 7 | * 需要定义增加调料 8 | */ 9 | @Override 10 | void addCondiments() { 11 | System.out.println("Steeping the tea"); 12 | } 13 | 14 | /** 15 | * 需要定义处理方法 16 | */ 17 | @Override 18 | void brew() { 19 | System.out.println("Adding Lemon"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch6-command/SimpleRemoteControl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 普通遥控器 3 | */ 4 | public class SimpleRemoteControl { 5 | Command slot;//有一个插槽持有命令,而这个命令控制着一个装置 6 | public SimpleRemoteControl(){ 7 | 8 | } 9 | 10 | /** 11 | * 这个方法用来设置插槽控制的命令.如果这段代码的客户想要改变遥控器按钮的行为,可以多次调用这个方法 12 | * @param command 13 | */ 14 | public void setCommand(Command command){ 15 | slot=command; 16 | } 17 | public void buttonWasPressed(){ 18 | slot.execute(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch8-template-method/CoffeeCaffeineBeverageImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 继承自咖啡因饮料 3 | */ 4 | public class CoffeeCaffeineBeverageImpl extends CaffeineBeverage { 5 | /** 6 | * 需要定义增加什么调料 7 | */ 8 | @Override 9 | void addCondiments() { 10 | System.out.println("Adding Sugar and Milk"); 11 | } 12 | 13 | /** 14 | * 咖啡需要定义处理方法 15 | */ 16 | @Override 17 | void brew() { 18 | System.out.println("Dripping Coffee through filter"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch1-interface/Test.java: -------------------------------------------------------------------------------- 1 | public class Test { 2 | public static void main(String args[]){ 3 | MallardDuck mallardDuck=new MallardDuck(); 4 | mallardDuck.display(); 5 | mallardDuck.performFly(); 6 | mallardDuck.performQuack(); 7 | 8 | 9 | //搞一只模型鸭 10 | ModelDuck md=new ModelDuck(); 11 | md.performFly();//第一次调用飞行时,委托给FlyNoWay 12 | md.setFlyBehavior(new FlyWithRocket());//继承来的设置飞行模式的方法,给予火箭动力 13 | md.performFly();//现在能飞啦~ 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ch6-command/LightOnCommand.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开电灯命令,这是一个命令,所以需要实现Command接口 3 | */ 4 | public class LightOnCommand implements Command { 5 | Light light; 6 | 7 | /** 8 | * execute方法调用接收对象的on()方法 9 | */ 10 | @Override 11 | public void execute() { 12 | light.on(); 13 | } 14 | 15 | /** 16 | * 构造器传入了某个灯泡,以便让这个命令控制,一旦调用execute(),就由这个对象成为接收者,负责接受请求 17 | * @param light 18 | */ 19 | public LightOnCommand(Light light){ 20 | this.light=light; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch6-command/LightOffCommand.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 开电灯命令,这是一个命令,所以需要实现Command接口 3 | */ 4 | public class LightOffCommand implements Command { 5 | Light light; 6 | 7 | /** 8 | * execute方法调用接收对象的on()方法 9 | */ 10 | @Override 11 | public void execute() { 12 | light.off(); 13 | } 14 | 15 | /** 16 | * 构造器传入了某个灯泡,以便让这个命令控制,一旦调用execute(),就由这个对象成为接收者,负责接受请求 17 | * @param light 18 | */ 19 | public LightOffCommand(Light light){ 20 | this.light=light; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch4-factory/SimplePizzaFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 简单工厂 3 | * 披萨工厂类 4 | */ 5 | public class SimplePizzaFactory { 6 | /** 7 | * 首先,在这个工厂类定义一个createPizza()方法,所有客户使用这个方法来实例化对象 8 | * @param type:披萨类型 9 | * @return Pizza 10 | */ 11 | public Pizza createPizza(String type){ 12 | Pizza pizza=null; 13 | if(type.equals("cheese")){ 14 | pizza=new CheesePizza(); 15 | }else if(type.equals("pepperoni")){ 16 | pizza=new Pepperoni(); 17 | } 18 | 19 | return pizza; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch3-decoration/Beverge/Mocha.java: -------------------------------------------------------------------------------- 1 | package Beverge; 2 | 3 | /** 4 | * 摩卡一种调味方式,扩展自调味类 5 | * Created by jimersylee on 17-8-19. 6 | */ 7 | public class Mocha extends CondimentDecorator { 8 | Beverage beverage; 9 | 10 | public Mocha(Beverage beverage) { 11 | this.beverage = beverage; 12 | } 13 | 14 | @Override 15 | public String getDescription() { 16 | return beverage.getDescription()+",Mocha"; 17 | } 18 | 19 | @Override 20 | public double cost() { 21 | return beverage.cost()+0.20; 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ch3-decoration/Beverge/Soy.java: -------------------------------------------------------------------------------- 1 | package Beverge; 2 | 3 | /** 4 | * Soy,一种调味方式,扩展调味类 5 | * 名字叫Soy,价格0.3 6 | * Created by jimersylee on 17-8-19. 7 | */ 8 | public class Soy extends CondimentDecorator { 9 | Beverage beverage; 10 | 11 | public Soy(Beverage beverage) { 12 | this.beverage = beverage; 13 | } 14 | 15 | @Override 16 | public String getDescription() { 17 | return beverage.getDescription()+",Soy"; 18 | } 19 | 20 | @Override 21 | public double cost() { 22 | return beverage.cost()+0.30; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ch3-decoration/Beverge/Whip.java: -------------------------------------------------------------------------------- 1 | package Beverge; 2 | 3 | /** 4 | * Whip.奶泡.一种调味方式,扩展自调味类 5 | * 名字 Whip,价格0.5 6 | * Created by jimersylee on 17-8-19. 7 | */ 8 | public class Whip extends CondimentDecorator { 9 | Beverage beverage; 10 | 11 | public Whip(Beverage beverage) { 12 | this.beverage = beverage; 13 | } 14 | 15 | @Override 16 | public String getDescription() { 17 | return beverage.getDescription()+",Whip"; 18 | } 19 | 20 | @Override 21 | public double cost() { 22 | return beverage.cost()+0.5; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ch8-template-method/Tea.java: -------------------------------------------------------------------------------- 1 | public class Tea { 2 | void prepareRecipe(){ 3 | boilWater(); 4 | steepTeaBag(); 5 | pourInCup(); 6 | addLemon(); 7 | } 8 | 9 | private void addLemon() { 10 | System.out.println("addLemon"); 11 | } 12 | 13 | private void pourInCup() { 14 | System.out.println("pourInCup"); 15 | } 16 | 17 | private void steepTeaBag() { 18 | System.out.println("steepTeaBag"); 19 | } 20 | 21 | private void boilWater() { 22 | System.out.println("boilWater"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ch6-command/RemoteControlTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 遥控器使用测试,这是命令模式的客户 3 | */ 4 | public class RemoteControlTest { 5 | public static void main(String[] args){ 6 | //遥控器就是调用者,会传入一个命令对象,可以用来发出请求 7 | SimpleRemoteControl remoteControl=new SimpleRemoteControl(); 8 | //创建了一个电灯对象,此对象也就是请求的接收者 9 | Light light=new Light(); 10 | //这里创建一个命令,然后将接收者传给它 11 | LightOnCommand lightOnCommand=new LightOnCommand(light); 12 | //设置命令 13 | remoteControl.setCommand(lightOnCommand); 14 | //调用命令 15 | remoteControl.buttonWasPressed(); 16 | } 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /ch4-factory/PizzaStore.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 披萨店类 3 | */ 4 | public class PizzaStore { 5 | /** 6 | * 为PizzaStore加上一个对SimplePizzaFactory的引用 7 | */ 8 | SimplePizzaFactory factory; 9 | 10 | /** 11 | * 构造器需要一个工厂作为一个参数 12 | * @param factory 13 | */ 14 | public PizzaStore(SimplePizzaFactory factory) { 15 | this.factory = factory; 16 | } 17 | 18 | public Pizza orderPizza(String type){ 19 | Pizza pizza=this.factory.createPizza(type); 20 | pizza.prepare(); 21 | pizza.bake(); 22 | pizza.cut(); 23 | pizza.box(); 24 | 25 | return pizza; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ch8-template-method/Coffee.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 这是我们的咖啡类,用来煮咖啡 3 | */ 4 | public class Coffee { 5 | void prepareRecipe(){ 6 | boilWater(); 7 | brewCoffeeGrinds(); 8 | pourInCup(); 9 | addSugarAndMilk(); 10 | } 11 | 12 | private void addSugarAndMilk() { 13 | System.out.println("addSugarAndMilk"); 14 | } 15 | 16 | private void pourInCup() { 17 | System.out.println("pourInCup"); 18 | } 19 | 20 | private void brewCoffeeGrinds() { 21 | System.out.println("brewCoffeeGrinds"); 22 | } 23 | 24 | private void boilWater() { 25 | System.out.println("boilWater"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ch7-adapter/DuckTestDrive.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 测试适配器 3 | */ 4 | public class DuckTestDrive { 5 | public static void main(String[] args){ 6 | //先创建一只鸭子 7 | MallardDuckImpl duck=new MallardDuckImpl(); 8 | //创建一只火鸡 9 | WildTurkey turkey=new WildTurkey(); 10 | //然后将火鸡包装进一个火鸡适配器中,使它看起来想一直鸭子 11 | IDuck turkeyAdapter=new TurkeyAdapterImpl(turkey); 12 | 13 | //测试火鸡 14 | turkey.gobble(); 15 | turkey.fly(); 16 | 17 | //测试真正的鸭子 18 | duck.quack(); 19 | duck.fly(); 20 | 21 | //测试假装是鸭子的火鸡 22 | turkeyAdapter.quack(); 23 | turkeyAdapter.fly(); 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ch3-decoration/Beverge/StarbuzzCoffee.java: -------------------------------------------------------------------------------- 1 | package Beverge; 2 | 3 | /** 4 | * 饮料店测试类 5 | * Created by jimersylee on 17-8-19. 6 | */ 7 | public class StarbuzzCoffee { 8 | public static void main(String[] args){ 9 | //订一杯咖啡,不要调料 10 | Beverage beverage=new Espresso(); 11 | System.out.println(beverage.getDescription()+" $"+beverage.cost()); 12 | 13 | //订一杯深度烘焙咖啡,双份摩卡,奶泡 14 | Beverage beverage1=new DarkRoast(); 15 | beverage1=new Mocha(beverage1); 16 | beverage1=new Mocha(beverage1); 17 | beverage1=new Whip(beverage1); 18 | System.out.println(beverage1.getDescription()+" $"+beverage1.cost()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch8-template-method/CaffeineBeverage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 咖啡因饮料是一个抽象类 3 | */ 4 | public abstract class CaffeineBeverage { 5 | final void prepareRecipe() { 6 | boilWater(); 7 | brew(); 8 | pourInCup(); 9 | addCondiments(); 10 | } 11 | 12 | /** 13 | * 因为咖啡和茶处理这些方法的做法不同,所以这两个方法必须被声明为抽象,剩余的东西留给子类去操心 14 | */ 15 | abstract void addCondiments(); 16 | 17 | /** 18 | * 因为咖啡和茶处理这些方法的做法不同,所以这两个方法必须被声明为抽象,剩余的东西留给子类去操心 19 | */ 20 | abstract void brew(); 21 | 22 | void pourInCup() { 23 | System.out.println("pourInCup"); 24 | } 25 | 26 | void boilWater() { 27 | System.out.println("boilWater"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ch5-singleton/SingletonEagerly.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 单例模式之饿汉模式 3 | * 过程:在程序启动的时候,静态初始化器中创建单例 4 | * 优点:如果程序对获取实例要求延迟低,则使用此模式,可以在多线程中使用\ 5 | * 缺点:程序初始化的时候,会减慢速度 6 | */ 7 | public class SingletonEagerly { 8 | /** 9 | * 利用一个静态变量来记录Singleton类的唯一实例 10 | * 在静态初始化器(static initialize)中创建单例.这段代码保证了线程安全(Thread Safe) 11 | */ 12 | private static SingletonEagerly instance=new SingletonEagerly(); 13 | 14 | /** 15 | * 构造器声明为私有的,只有自己Singleton类才可以调用构造器 16 | */ 17 | private SingletonEagerly() { 18 | } 19 | 20 | /** 21 | * 用getInstance()实例化对象,并返回这个实例 22 | * 方法不必用synchronized关键字修饰 23 | * @return 24 | */ 25 | public static SingletonEagerly getInstance() { 26 | return instance; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DesignPattern 2 | <Head first :Design Pattern> 学习笔记 3 | 4 | 5 | ## 面向对象基础 6 | - 抽象 7 | - 封装 8 | - 多态 9 | - 继承 10 | 11 | ## 设计原则 12 | - 封装变化 13 | - 多用组合,少用继承 14 | - 找出程序中会变化的方面,然后将其和固定不变的方面相分离 15 | - 针对接口编程,不针对实现编程 16 | - 为交互对象之间的松耦合设计而努力 17 | - 类应该对扩展开放,对修改关闭 18 | - 最少知识原则:尽量与一个对象交互 19 | - 好莱坞原则:别底样我们,我们会调用你 20 | 21 | ## OO模式 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 | -------------------------------------------------------------------------------- /ch3-decoration/README.md: -------------------------------------------------------------------------------- 1 | # 装饰者模式 2 | 3 | 本章可以称为"给爱用继承的人一个全新的设计眼界" 4 | 5 | 装饰者和呗装饰对象有相同的超类型. 6 | 可以用一个或者多个装饰者包装一个对象. 7 | 既然装饰者和被装饰对象具有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它 8 | 9 | **装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定的目的** 10 | 11 | 对象可以在任何时候被装饰,所以在运行时动态地,不限量地用你喜欢的装饰者来装饰对象 12 | 13 | ##定义装饰者模式 14 | >装饰者模式动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案 15 | 16 | 17 | 18 | Beverge 星巴兹咖啡装饰者实现 19 | IO Java的装饰者模式实现 20 | 21 | 22 | ##要点 23 | - 继承属于扩展形式之一,但不见得事达到弹性设计的最佳方式 24 | - 在设计中,应该允许行为被扩展,二不许修改现有的代码 25 | - 组合和委托可用于在运行时动态的加上新的行为 26 | - 除了继承,装饰者模式也可以让我们扩展行为 27 | - 装饰者模式意味着一群装饰者类,这些类用来包装具体组件 28 | - 装饰这类反映出被装饰的组件类型,(事实上,他们具有相同的类型,都经过接口或者继承实现) 29 | - 装饰者可以在被装饰者的行为前面或者侯建加上自己的行为,甚至将被装饰者的行为整个取代掉,从而达到特定的目的 30 | - 你可以用无数个装饰者包装一个组件 31 | - 装饰者一般对组件的客户事透明的,除非客户程序依赖于组件的具体类型 32 | - 装饰者会导致设计中出现许多的小对象,如果过度使用,会让程序变得很复杂 33 | - 34 | 35 | 36 | -------------------------------------------------------------------------------- /ch7-adapter/TurkeyAdapterImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 火鸡假装鸭子的适配器,首先,你需要实现想转换成的类型接口,也就是你的客户所期望看到的接口 3 | */ 4 | public class TurkeyAdapterImpl implements IDuck { 5 | Turkey turkey; 6 | 7 | /** 8 | * 接着,需要取得要适配的对象引用,这里我们利用构造器取得这个引用 9 | * @param turkey:火鸡对象 10 | */ 11 | public TurkeyAdapterImpl(Turkey turkey){ 12 | this.turkey=turkey; 13 | } 14 | 15 | /** 16 | * 现在我们需要实现接口中所有的方法,quack()在类之间的转换很简单,只要调用gobble()就可以了 17 | */ 18 | @Override 19 | public void quack() { 20 | turkey.gobble(); 21 | } 22 | 23 | /** 24 | * 虽然两个接口都具备了fly方法(),火鸡的飞行距离很短,不想鸭子可以长途飞行,要让鸭子可以长途飞行.要让鸭子的飞行和火鸡的飞行能够对应,必须连续5此调用火鸡的fly()来完成 25 | */ 26 | @Override 27 | public void fly() { 28 | for(int i=0;i<5;i++){ 29 | turkey.fly(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ch5-singleton/SingletonLazy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 单例模式之懒汉模式 3 | * 优点:在需要实例的时候才进行第一次实例化,在资源紧缺的时候,可以减少不必要的资源消耗 4 | * 缺点:同步了getInstance(),会造成性能浪费 5 | */ 6 | public class SingletonLazy { 7 | /** 8 | * 利用一个静态变量来记录Singleton类的唯一实例 9 | */ 10 | private static SingletonLazy instance; 11 | 12 | /** 13 | * 构造器声明为私有的,只有自己Singleton类才可以调用构造器 14 | */ 15 | private SingletonLazy() { 16 | 17 | } 18 | 19 | /** 20 | * 用getInstance()实例化对象,并返回这个实例 21 | * 在多线程中必须使用synchronized关键字修饰 22 | * @return 23 | */ 24 | public static synchronized SingletonLazy getInstance() { 25 | 26 | //懒汉模式 27 | //如果未被实例化,则new 28 | if (instance == null) { 29 | instance = new SingletonLazy(); 30 | } 31 | //如果已经实例化,则返回实例 32 | return instance; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ch5-singleton/ChocolateBoiler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 巧克力工厂,非单例 3 | */ 4 | public class ChocolateBoiler { 5 | private boolean empty; 6 | private boolean boiled; 7 | 8 | /** 9 | * 代码开始时,锅炉是空的 10 | */ 11 | public ChocolateBoiler(){ 12 | empty=true; 13 | boiled=false; 14 | } 15 | 16 | /** 17 | * 在锅炉内填入原料时,锅炉必须是空的.一旦填入原料,就把empty和boiled标识设置好. 18 | */ 19 | public void fill() { 20 | if (isEmpty()) { 21 | empty = false; 22 | boiled = false; 23 | } 24 | } 25 | 26 | public void boil() { 27 | if (!isEmpty() && !isBoiled()) { 28 | //将炉内物煮沸 29 | boiled = true; 30 | } 31 | } 32 | 33 | public boolean isEmpty() { 34 | return empty; 35 | } 36 | public boolean isBoiled() { 37 | return boiled; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ch3-decoration/IO/InputTest.java: -------------------------------------------------------------------------------- 1 | package IO; 2 | 3 | import java.io.*; 4 | 5 | /** 6 | * 新的I/O装饰者测试类,用来测试将输入转换为小写 7 | * Created by jimersylee on 17-8-20. 8 | */ 9 | public class InputTest { 10 | 11 | public static void main(String[] args){ 12 | int c; 13 | try { 14 | //设置FileInputStream 15 | //先用BufferedInputStream装饰 16 | //再用我们崭新的LowerCaseInputStream装饰 17 | InputStream in=new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("/home/jimersylee/project/java/DesignPattern/ch3/IO/test.txt"))); 18 | while ((c=in.read())>=0){ 19 | System.out.print((char)c); 20 | } 21 | in.close(); 22 | 23 | 24 | } catch (FileNotFoundException e) { 25 | e.printStackTrace(); 26 | } catch (IOException e) { 27 | e.printStackTrace(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ch6-command/RemoteControl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 高级遥控器 3 | */ 4 | public class RemoteControl { 5 | Command[] onCommands; 6 | Command[] offCommands; 7 | public RemoteControl(){ 8 | onCommands=new Command[7]; 9 | offCommands =new Command[7]; 10 | Command noCommand=new NoCommand(); 11 | for(int i=0;i<7;i++){ 12 | onCommands[i]=noCommand; 13 | offCommands[i]=noCommand; 14 | } 15 | 16 | } 17 | 18 | /** 19 | * 这个方法用来设置插槽控制的命令.如果这段代码的客户想要改变遥控器按钮的行为,可以多次调用这个方法 20 | * @param 21 | */ 22 | public void setCommand(int slot,Command onCommand,Command offCommand){ 23 | onCommands[slot]=onCommand; 24 | offCommands[slot]=offCommand; 25 | } 26 | public void onButtonWasPushed(int slot){ 27 | onCommands[slot].execute(); 28 | } 29 | public void offButtonWasPushed(int slot){ 30 | offCommands[slot].execute(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ch7-adapter/README.md: -------------------------------------------------------------------------------- 1 | # 适配器模式与外观模式 2 | 3 | 4 | ## 适配器模式 5 | ### 需求 6 | 现在已经存在IDuck接口,Turkey接口,假设你缺鸭子对象,想用一些火鸡对象来冒充.显而易见,因为火鸡的接口不同,所以我们不能公然拿来用,那么写个适配器吧 7 | 8 | 9 | ### FAQ 10 | - 一个适配器需要做多少适配工作? 11 | >实现一个适配器所需要进行的工作,和目标接口的大小成正.如果不用适配器,你就必须改写客户端的代码来调用这个新的接口.相比之下,使用适配器成本更少 12 | 13 | - 一个适配器只能封装一个类吗? 14 | >虽然大多数的适配器模式所采取的例子都是让一个适配器包装一个被适配者,但还是会有状况需要让一个适配器包装多个被适配者.这设计到另一个模式,被称为外观模式(Facade Pattern),人们常常将外观模式和适配器模式混为一谈,本章稍后对此详细说明 15 | 16 | - 万一我的系统中新旧并存,是不是不使用适配器更好 17 | >可以创建一个双向的适配器,支持两边的接口.这样,这个适配器可以当做旧的接口,或者当做新的接口使用 18 | 19 | 20 | ## 外观模式 21 | >外观模式提供了一个统一的接口,用来访问子系统中的一群接口.外观定了一个高层接口,让子系统更容易使用. 22 | 23 | 外观模式的意图是提供一个简单的接口,好让一个子系统更易于使用 24 | 25 | 26 | ## 要点 27 | - 当需要使用一个现有的类而其接口并不符合你的需求时,就使用适配器 28 | - 当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观 29 | - 适配器改变接口以符合客户的期望 30 | - 外观将客户从一个复杂的子系统中解耦 31 | - 实现一个适配器可能需要一番功夫,也可能不费功夫,视目标接口的大小与复杂度而定 32 | - 实现一个外观,需要将子系统组合进外观中,然后将工作委托给给子系统执行 33 | - 适配器模式有两种形式:对象适配器和类适配器.类适配器需要用到多重继承 34 | - 你可以为一个子系统实现一个以上的外观 35 | - 适配器将一个对象包装起来以改变其接口;装饰着将一个对象包装起来以增加新的行为和责任;而外观将一群对象"包装"起来以简化其接口 36 | 37 | -------------------------------------------------------------------------------- /ch2-observer/Observable/WeatherData.java: -------------------------------------------------------------------------------- 1 | package Observable; 2 | 3 | import java.util.Observable; 4 | 5 | /** 6 | * 使用java.util内置的观察者模式实现 7 | * Created by jimersylee on 17-8-19. 8 | */ 9 | public class WeatherData extends Observable { 10 | private float temperature; 11 | private float humidity; 12 | private float pressure; 13 | 14 | 15 | public WeatherData() { 16 | 17 | } 18 | 19 | public void measurementsChanged() { 20 | setChanged(); 21 | notifyObservers(); 22 | } 23 | 24 | public float getTemperature() { 25 | return temperature; 26 | } 27 | 28 | public float getHumidity() { 29 | return humidity; 30 | } 31 | 32 | public float getPressure() { 33 | return pressure; 34 | } 35 | 36 | public void setMeasurements(float temperature, float humidity, float pressure) { 37 | this.temperature = temperature; 38 | this.humidity = humidity; 39 | this.pressure = pressure; 40 | measurementsChanged(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ch2-observer/Observable/CurrentConditionDisplay.java: -------------------------------------------------------------------------------- 1 | package Observable; 2 | 3 | import java.util.Observable; 4 | import java.util.Observer; 5 | 6 | /** 7 | * 天气状况布告板 8 | * Created by jimersylee on 17-8-19. 9 | */ 10 | public class CurrentConditionDisplay implements Observer,DisplayElement { 11 | Observable observable; 12 | private float temperature; 13 | private float humidity; 14 | 15 | public CurrentConditionDisplay(Observable observable){ 16 | this.observable=observable; 17 | observable.addObserver(this); 18 | } 19 | 20 | 21 | public void update(Observable obs,Object arg){ 22 | if(obs instanceof WeatherData){ 23 | WeatherData weatherData=(WeatherData)obs; 24 | this.temperature=weatherData.getTemperature(); 25 | this.humidity=weatherData.getHumidity(); 26 | display(); 27 | } 28 | } 29 | 30 | public void display(){ 31 | System.out.println("Current conditions:"+temperature+"F degrees and "+humidity+"% humidity"); 32 | } 33 | 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /ch2-observer/CurrentConditionDisplay.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 公告板实现 3 | */ 4 | public class CurrentConditionDisplay implements Observer,DisplayElement { 5 | private float temperature; 6 | private float humidity; 7 | private Subject weatherData; 8 | 9 | /** 10 | * 构造器需要weatherData对象(也就是主题)作为注册之用 11 | * @param weatherData:天气对象 12 | */ 13 | public CurrentConditionDisplay(Subject weatherData){ 14 | this.weatherData=weatherData; 15 | weatherData.registerObserver(this); 16 | } 17 | 18 | /** 19 | * display()方法就只是把最近的问的和湿度显示出来 20 | */ 21 | @Override 22 | public void display() { 23 | System.out.println("Current conditions:"+temperature+"F degree and "+humidity+"% humidity"); 24 | } 25 | 26 | /** 27 | * 当update被调用时,我们把温度和湿度保存起来,然后调用display 28 | * @param temp 29 | * @param humidity 30 | * @param pressure 31 | */ 32 | @Override 33 | public void update(float temp, float humidity, float pressure) { 34 | this.temperature=temp; 35 | this.humidity=humidity; 36 | display(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ch5-singleton/SingletonDoubleCheckedLocking.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 单例模式之使用"双重检查加锁" 3 | * 过程:在getInstance()中进行双重检查,确保一个实例 4 | * 优点:在getInstance()中减少同步,增强性能,可以在多线程中使用 5 | * 缺点:暂无 6 | */ 7 | public class SingletonDoubleCheckedLocking { 8 | /** 9 | * 利用一个静态变量来记录Singleton类的唯一实例 10 | * volatile关键字确保:当instance变量被初始化为Singleton实例时,多个线程正确地处理instance变量 11 | */ 12 | private static volatile SingletonDoubleCheckedLocking instance; 13 | 14 | /** 15 | * 构造器声明为私有的,只有自己Singleton类才可以调用构造器 16 | */ 17 | private SingletonDoubleCheckedLocking() { 18 | } 19 | 20 | /** 21 | * 用getInstance()实例化对象,并返回这个实例 22 | * 方法不必用synchronized关键字修饰 23 | * @return 24 | */ 25 | public static SingletonDoubleCheckedLocking getInstance() { 26 | if(instance==null){//检查实例,如果不存在,则进入同步区块 27 | //注意:只有第一次调用getInstance()方法才彻底执行这里的代码 28 | synchronized (SingletonDoubleCheckedLocking.class){ 29 | if(instance==null){//进入区块后,再检查一次,如果是null,才创建实例 30 | instance=new SingletonDoubleCheckedLocking(); 31 | } 32 | } 33 | } 34 | 35 | return instance; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ch5-singleton/ChocolateBoilerSingleton.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 巧克力工厂,单例模式 3 | */ 4 | public class ChocolateBoilerSingleton { 5 | private boolean empty; 6 | private boolean boiled; 7 | private static ChocolateBoilerSingleton instance; 8 | 9 | /** 10 | * 代码开始时,锅炉是空的 11 | */ 12 | private ChocolateBoilerSingleton(){ 13 | empty=true; 14 | boiled=false; 15 | } 16 | 17 | 18 | public static synchronized ChocolateBoilerSingleton getInstance(){ 19 | if(instance==null){ 20 | instance=new ChocolateBoilerSingleton(); 21 | } 22 | 23 | return instance; 24 | } 25 | 26 | /** 27 | * 在锅炉内填入原料时,锅炉必须是空的.一旦填入原料,就把empty和boiled标识设置好. 28 | */ 29 | public void fill() { 30 | if (isEmpty()) { 31 | empty = false; 32 | boiled = false; 33 | } 34 | } 35 | 36 | public void boil() { 37 | if (!isEmpty() && !isBoiled()) { 38 | //将炉内物煮沸 39 | boiled = true; 40 | } 41 | } 42 | 43 | public boolean isEmpty() { 44 | return empty; 45 | } 46 | public boolean isBoiled() { 47 | return boiled; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ch4-factory/README.md: -------------------------------------------------------------------------------- 1 | #工厂模式 2 | 针对接口编程,可以隔离掉以后系统可能发生的一大堆改变 3 | 为了让系统有弹性,我们希望一个类是抽象类或接口.但如果这样,这些类或接口就无法直接实例化 4 | 根据类的类型,我们实例化正确的具体类,然后返回具体类的对象,这些具体类必须实现抽象类接口 5 | 但是压力来自于增加更多的具体类类型 6 | 把创建对象的代码从具体方法中抽离,把创建的过程搬到另一个对象中,这个对象只管如何创建对象. 7 | 我们称这个对象为*工厂*,现在我们就来实现一个披萨工厂 8 | 9 | 10 | ##简单工厂模式 11 | 创建对象的过程在工厂类中 12 | ``` 13 | /** 14 | * 简单工厂 15 | * 披萨工厂类 16 | */ 17 | public class SimplePizzaFactory { 18 | /** 19 | * 首先,在这个工厂类定义一个createPizza()方法,所有客户使用这个方法来实例化对象 20 | * @param type:披萨类型 21 | * @return Pizza 22 | */ 23 | public Pizza createPizza(String type){ 24 | Pizza pizza=null; 25 | if(type.equals("cheese")){ 26 | pizza=new CheesePizza(); 27 | }else if(type.equals("pepperoni")){ 28 | pizza=new Pepperoni(); 29 | } 30 | 31 | return pizza; 32 | } 33 | } 34 | ``` 35 | 36 | 37 | 38 | ##工厂方法模式 39 | 工厂方法用来处理对象的创建,并将这样的行为封装在子类中.这样,客户程序中关于超类的代码就和子类对象创建代码解耦了.工厂方法可能需要参数,也可能不需要. 40 | ``` 41 | abstract Product factoryMethod(String type) 42 | abstract:工厂方法是抽象的 43 | Product:工厂方法必须返回一个产品.超类中定义的方法,通常使用工厂方法的返回值 44 | factoryMethod:工厂方法将客户(也就是超类中的代码,列入orderPizza())和实际创建具体产品的代码分割开来 45 | type:工厂方法可能需要/不需要参数来制定所要的产品 46 | ``` 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /ch2-observer/WeatherData.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | 3 | /** 4 | * 天气数据类实现了Subject(主题)接口 5 | */ 6 | public class WeatherData implements Subject { 7 | private ArrayList observers; 8 | private float temperature; 9 | private float humidity; 10 | private float pressure; 11 | 12 | 13 | public WeatherData(){ 14 | observers=new ArrayList<>(); 15 | } 16 | 17 | @Override 18 | public void registerObserver(Observer o) { 19 | observers.add(o); 20 | } 21 | 22 | @Override 23 | public void removeObserver(Observer o) { 24 | int i=observers.indexOf(o); 25 | if(i>=0){ 26 | observers.remove(i); 27 | } 28 | } 29 | 30 | @Override 31 | public void notifyObservers() { 32 | for (Observer observer : observers) { 33 | observer.update(temperature, humidity, pressure); 34 | } 35 | } 36 | 37 | /** 38 | * 此方法会在气象值变化时被调用 39 | */ 40 | public void measurementsChanged(){ 41 | notifyObservers(); 42 | } 43 | 44 | 45 | public void setMeasurements(float temperature,float humidity,float pressure){ 46 | this.temperature=temperature; 47 | this.humidity=humidity; 48 | this.pressure=pressure; 49 | measurementsChanged(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ch3-decoration/IO/LowerCaseInputStream.java: -------------------------------------------------------------------------------- 1 | package IO; 2 | 3 | import java.io.FilterInputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | /** 8 | * 利用装饰者模式实现一个将输入转换为小写的类 9 | * FilterInputStream:所有InputStream的抽象装饰者 10 | * LowerCaseInputStream:InputStream的具体装饰者 11 | * Created by jimersylee on 17-8-20. 12 | */ 13 | public class LowerCaseInputStream extends FilterInputStream { 14 | /** 15 | * Creates a FilterInputStream 16 | * by assigning the argument in 17 | * to the field this.in so as 18 | * to remember it for later use. 19 | * 20 | * @param in the underlying input stream, or null if 21 | * this instance is to be created without an underlying stream. 22 | */ 23 | public LowerCaseInputStream(InputStream in) { 24 | super(in); 25 | } 26 | 27 | public int read() throws IOException { 28 | int c=super.read(); 29 | return (c==-1?c:Character.toLowerCase((char)c)); 30 | } 31 | 32 | public int read(byte[] b,int offset,int len) throws IOException{ 33 | int result=super.read(b,offset,len); 34 | for(int i=offset;i模板方法模式在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤 6 | 7 | 这个模式是用来创建一个算法的模板.什么是模板?模板就是一个方法.更具体地说,这个方法将算法定义为一组步骤,其中的任何步骤都可以是抽象的,由子类负责实现.这可以确保算法的结构保持不变,同时由子类提供部分实现. 8 | 9 | 10 | # 快速搞定咖啡和茶的类 11 | 12 | ``` 13 | /** 14 | * 这是我们的咖啡类,用来煮咖啡 15 | */ 16 | public class Coffee { 17 | void prepareRecipe(){ 18 | boilWater(); 19 | brewCoffeeGrinds(); 20 | pourInCup(); 21 | addSugarAndMilk(); 22 | } 23 | 24 | private void addSugarAndMilk() { 25 | System.out.println("addSugarAndMilk"); 26 | } 27 | 28 | private void pourInCup() { 29 | System.out.println("pourInCup"); 30 | } 31 | 32 | private void brewCoffeeGrinds() { 33 | System.out.println("brewCoffeeGrinds"); 34 | } 35 | 36 | private void boilWater() { 37 | System.out.println("boilWater"); 38 | } 39 | } 40 | 41 | 42 | public class Tea { 43 | void prepareRecipe(){ 44 | boilWater(); 45 | steepTeaBag(); 46 | pourInCup(); 47 | addLemon(); 48 | } 49 | 50 | private void addLemon() { 51 | System.out.println("addLemon"); 52 | } 53 | 54 | private void pourInCup() { 55 | System.out.println("pourInCup"); 56 | } 57 | 58 | private void steepTeaBag() { 59 | System.out.println("steepTeaBag"); 60 | } 61 | 62 | private void boilWater() { 63 | System.out.println("boilWater"); 64 | } 65 | } 66 | 67 | 68 | 69 | ``` 70 | 71 | 请注意,boilWater()和pourCup()这两个方法完全一样,也就是说这里出现了重复的代码 72 | 73 | 在这里,茶和咖啡是如此的相似,可以提取基类 74 | 75 | 76 | 注意两份冲泡法都采用了相同的算法 77 | 78 | 抽象prepareRecipe() 79 | 80 | 81 | ``` 82 | void prepareRecipe(){ 83 | boilwater(); 84 | brew(); 85 | pourInCup(); 86 | addCondiments(); 87 | } 88 | 89 | ``` 90 | 91 | 92 | 93 | prepareRecipe()就是我们的模板方法 94 | - 它是一个方法 95 | - 它用作一个算法的模板,在这个例子中,算法是用来制作咖啡饮料的 96 | - 在这个模板中,算法内的每一个步骤都被一个方法代表了 97 | - 某些方法是由这个类(也就是超类)处理的 98 | - 某些方法是由子类处理的 99 | - 需要由子类提供的方法,必须在超类中声明为抽象 100 | 101 | 102 | ## 优劣对比 103 | 不好的茶和咖啡的实现 104 | - Coffee和Tea主导一切;他们控制了算法 105 | - Coffee和Tea之间存在重复的代码 106 | - 对于算法所做的代码改变,需要打开子类修改许多地方 107 | - 由于类的组织方式不具有弹性,所以加入新种类的咖啡因饮料需要做许多工作 108 | - 算法的知识和它的实现会分散在很多类中 109 | 110 | 模板方法提供的酷炫咖啡因饮料 111 | - 由CaffeineBeverage类主导一切,它拥有算法,而且保护这个算法 112 | - 对子类来说,CaffeineBeverage类的存在,可以将代码的复用最大化 113 | - 算法只存在于一个地方,所以容易修改 114 | - 这个模板方法提供了一个框架,可以让其他的咖啡因饮料插进来.新的咖啡因饮料只需要实现自己的方法就可以了 115 | - CaffeineBeverage类专注于算法本身,而子类提供完整的实现 116 | 117 | 118 | 119 | ## 要点 120 | - "模板方法"定义了算法的步骤,把这些步骤的实现延迟到子类 121 | - 模板方法模式为我们提供了一种代码复用的重要技巧 122 | - 模板方法的抽象类可以定义具体方法,抽象方法和钩子 123 | - 抽象方法由子类实现 124 | - 钩子是一种方法,它在抽象类中不做事,或者只做默认的事情,子类可以选择要不要去覆盖它 125 | - 为了防止子类改变模板方法中的算法,可以将模板方法声明为final 126 | - 好莱坞原则告诉我们,将决策权房子高层模块中,以便决定如何以及何时调用底层模块 127 | - 策略模式和模板方法模式都封装算法,一个用组合,一个用继承 128 | - 工厂方法是模板方法的一个特殊版本 129 | 130 | 131 | -------------------------------------------------------------------------------- /ch5-singleton/README.md: -------------------------------------------------------------------------------- 1 | # 单例模式 2 | ## 有什么用处 3 | 有些对象其实我们只需要一个,比方说:线程池,缓存,对话框,注册表,日志对象...如果制造出多个实例,就会导致许多问题产生,例如程序的行为异常,资源使用过量,数据不一致 4 | ## 如何做 5 | 利用静态类变量,静态方法和适当的访问修饰符 6 | 7 | ## 定义 8 | >单例模式,确保一个类只有一个实例,并提供一个全局访问点 9 | 10 | 11 | ## 注意点,多线程中使用单例 12 | 如果有多个线程同时调用getInstance(),可能会产生多个实例,那就用synchronized(同步)关键字修饰 13 | 但是同步会降低性能,实际上也就第一次getInstance()时需要考虑同步问题,之后就没有同步问题. 14 | 15 | ## 1.如果getInstance()的性能对应用程序不是很关键,就加上synchronized关键字 16 | 17 | ``` 18 | /** 19 | * 单例模式之懒汉模式 20 | * 优点:在需要实例的时候才进行第一次实例化,在资源紧缺的时候,可以减少不必要的资源消耗 21 | * 缺点:同步了getInstance(),会造成性能浪费 22 | */ 23 | public class SingletonLazy { 24 | /** 25 | * 利用一个静态变量来记录Singleton类的唯一实例 26 | */ 27 | private static SingletonLazy instance; 28 | 29 | /** 30 | * 构造器声明为私有的,只有自己Singleton类才可以调用构造器 31 | */ 32 | private SingletonLazy() { 33 | 34 | } 35 | 36 | /** 37 | * 用getInstance()实例化对象,并返回这个实例 38 | * 在多线程中必须使用synchronized关键字修饰 39 | * @return 40 | */ 41 | public static synchronized SingletonLazy getInstance() { 42 | 43 | //懒汉模式 44 | //如果未被实例化,则new 45 | if (instance == null) { 46 | instance = new SingletonLazy(); 47 | } 48 | //如果已经实例化,则返回实例 49 | return instance; 50 | } 51 | } 52 | 53 | ``` 54 | 55 | ## 2.如果getInstance()的性能对应用程序很关键,那就使用饿汉模式 56 | 使用饿汉模式 57 | 58 | ``` 59 | public class SingletonLazy{ 60 | //在静态初始化器(static initialize)中创建单例.这段代码保证了线程安全(Thread Safe) 61 | private static SingletonLazy instance=new SingletonLazy(); 62 | 63 | private SingletonLazy(){ 64 | } 65 | 66 | public static SingletonLazy getInstance(){ 67 | //到这里,一定存在实例了,直接使用它 68 | return instance; 69 | } 70 | 71 | 72 | } 73 | 74 | ``` 75 | 76 | ## 3.使用"双重检查锁"(double-checked locking),在getInstance()中减少使用同步 77 | ``` 78 | /** 79 | * 单例模式之使用"双重检查加锁" 80 | * 过程:在getInstance()中进行双重检查,确保一个实例 81 | * 优点:在getInstance()中减少同步,增强性能,可以在多线程中使用 82 | * 缺点:暂无 83 | */ 84 | public class SingletonDoubleCheckedLocking { 85 | /** 86 | * 利用一个静态变量来记录Singleton类的唯一实例 87 | * volatile关键字确保:当instance变量被初始化为Singleton实例时,多个线程正确地处理instance变量 88 | */ 89 | private static volatile SingletonDoubleCheckedLocking instance; 90 | 91 | /** 92 | * 构造器声明为私有的,只有自己Singleton类才可以调用构造器 93 | */ 94 | private SingletonDoubleCheckedLocking() { 95 | } 96 | 97 | /** 98 | * 用getInstance()实例化对象,并返回这个实例 99 | * 方法不必用synchronized关键字修饰 100 | * @return 101 | */ 102 | public static SingletonDoubleCheckedLocking getInstance() { 103 | if(instance==null){//检查实例,如果不存在,则进入同步区块 104 | //注意:只有第一次调用getInstance()方法才彻底执行这里的代码 105 | synchronized (SingletonDoubleCheckedLocking.class){ 106 | if(instance==null){//进入区块后,再检查一次,如果是null,才创建实例 107 | instance=new SingletonDoubleCheckedLocking(); 108 | } 109 | } 110 | } 111 | 112 | return instance; 113 | } 114 | } 115 | 116 | ``` 117 | --------------------------------------------------------------------------------