├── src └── com │ └── quyunshuo │ └── designpattern │ ├── structural │ ├── decorator │ │ ├── io │ │ │ ├── test.txt │ │ │ ├── Main.kt │ │ │ └── LowerCaseInputStream.kt │ │ ├── coffee │ │ │ ├── CondimentDecorator.kt │ │ │ ├── DarkRoast.kt │ │ │ ├── Beverage.kt │ │ │ ├── Espresso.kt │ │ │ ├── HouseBlend.kt │ │ │ ├── Soy.kt │ │ │ ├── Milk.kt │ │ │ ├── Mocha.kt │ │ │ └── Main.kt │ │ └── DecoratorPatternDoc.md │ ├── facade │ │ ├── Tuner.kt │ │ ├── CdPlayer.kt │ │ ├── TheaterLights.kt │ │ ├── Screen.kt │ │ ├── PopcornPopper.kt │ │ ├── Projector.kt │ │ ├── DvdPlayer.kt │ │ ├── Amplifier.kt │ │ ├── FacadePatternDoc.md │ │ ├── Main.kt │ │ └── HomeTheaterFacade.kt │ ├── adapter │ │ ├── duck │ │ │ ├── Duck.kt │ │ │ ├── Turkey.kt │ │ │ ├── MallardDuck.kt │ │ │ ├── WildTurkey.kt │ │ │ ├── TurkeyAdapter.kt │ │ │ └── Main.kt │ │ ├── AdapterPatternDoc.md │ │ └── iterator │ │ │ └── EnumerationIterator.java │ ├── StructuralPatternDoc.md │ └── composite │ │ ├── Waitress.kt │ │ ├── CompositePatternDoc.md │ │ ├── MenuItem.kt │ │ ├── Menu.kt │ │ ├── MenuComponent.kt │ │ └── Main.kt │ ├── creational │ ├── factory │ │ ├── abstract │ │ │ ├── Clams.kt │ │ │ ├── Cheese.kt │ │ │ ├── Dough.kt │ │ │ ├── FreshClams.kt │ │ │ ├── FrozenClams.kt │ │ │ ├── ThickCrustDough.kt │ │ │ ├── ThinCrustDough.kt │ │ │ ├── ShreddedMozzarellaCheese.kt │ │ │ ├── GratedReggianoCheese.kt │ │ │ ├── NYPizzaIngredientFactory.kt │ │ │ ├── CheesePizza.kt │ │ │ ├── ChicagoPizzaIngredientFactory.kt │ │ │ ├── PizzaIngredientFactory.kt │ │ │ ├── AbstractFactoryPatternDoc.md │ │ │ ├── NYPizzaStore.kt │ │ │ ├── PizzaStore.kt │ │ │ ├── ChicagoPizzaStore.kt │ │ │ ├── Pizza.kt │ │ │ └── Main.kt │ │ ├── simple │ │ │ ├── CheesePizza.kt │ │ │ ├── VeggiePizza.kt │ │ │ ├── PepperoniPizza.kt │ │ │ ├── SimpleFactoryPatternDoc.md │ │ │ ├── Main.kt │ │ │ ├── SimplePizzaFactory.kt │ │ │ ├── PizzaStore.kt │ │ │ └── Pizza.kt │ │ └── method │ │ │ ├── NYStyleCheesePizza.kt │ │ │ ├── NYPizzaStore.kt │ │ │ ├── ChicagoPizzaStore.kt │ │ │ ├── ChicagoStyleCheesePizza.kt │ │ │ ├── FactoryMethodPatternDoc.md │ │ │ ├── PizzaStore.kt │ │ │ ├── Pizza.kt │ │ │ └── Main.kt │ ├── singleton │ │ ├── kotlin │ │ │ ├── KtSingletonEnum.kt │ │ │ ├── KtSingleton.kt │ │ │ ├── KtSingletonStaticClass.kt │ │ │ ├── KtSingletonLock.kt │ │ │ └── KtSingletonDoubleLock.kt │ │ ├── SingletonPatternDoc.md │ │ └── java │ │ │ ├── SingletonEnum.java │ │ │ ├── SingletonLock.java │ │ │ ├── Singleton.java │ │ │ ├── SingletonStaticClass.java │ │ │ └── SingletonDoubleLock.java │ ├── builder │ │ ├── classic │ │ │ ├── Product.kt │ │ │ ├── Builder.kt │ │ │ ├── Director.kt │ │ │ ├── ConcreteBuilderA.kt │ │ │ └── ConcreteBuilderB.kt │ │ ├── BuilderPatternDoc.md │ │ └── variant1 │ │ │ ├── Main.kt │ │ │ └── User.java │ └── CreationalPatternDoc.md │ └── behavioral │ ├── strategy │ ├── QuackBehavior.kt │ ├── FlyBehavior.kt │ ├── Quack.kt │ ├── Squeak.kt │ ├── MuteQuack.kt │ ├── FlyNoWay.kt │ ├── FlyWithWings.kt │ ├── FlyRocketPowered.kt │ ├── ModelDuck.kt │ ├── MallardDuck.kt │ ├── StrategyPatternDoc.md │ ├── Main.kt │ └── Duck.kt │ ├── iterator │ ├── Menu.java │ ├── Iterator.kt │ ├── MenuItem.kt │ ├── IteratorPatternDoc.md │ ├── Waitress.java │ ├── Main.kt │ ├── PancakeHouseMenu.java │ └── DinerMenu.java │ ├── observer │ ├── DisplayElement.kt │ ├── ObserverPatternDoc.md │ ├── Observer.kt │ ├── Subject.kt │ ├── Main.kt │ ├── CurrentConditionsDisplay.kt │ └── WeatherData.kt │ ├── command │ ├── Command.kt │ ├── NoCommand.kt │ ├── MacroCommand.kt │ ├── Light.kt │ ├── LightOnCommand.kt │ ├── LightOffCommand.kt │ ├── StereoOffCommand.kt │ ├── StereoOnWithCDCommand.kt │ ├── SimpleRemoteControl.kt │ ├── Stereo.kt │ ├── CommandPatternDoc.md │ ├── CeilingFanLowCommand.kt │ ├── CeilingFanOffCommand.kt │ ├── CeilingFanHighCommand.kt │ ├── CeilingFanMediumCommand.kt │ ├── CeilingFan.kt │ ├── RemoteControl.kt │ └── Main.kt │ ├── template │ ├── Tea.kt │ ├── Coffee.kt │ ├── Main.kt │ ├── TemplatePatternDoc.md │ └── CaffeineBeverage.kt │ ├── BehavioralPatternDoc.md │ └── state │ ├── State.kt │ ├── StatePatternDoc.md │ ├── SoldOutState.kt │ ├── Main.kt │ ├── NoQuarterState.kt │ ├── SoldState.kt │ ├── HasQuarterState.kt │ ├── WinnerState.kt │ └── GumballMachine.kt ├── DesignPattern.iml └── README.md /src/com/quyunshuo/designpattern/structural/decorator/io/test.txt: -------------------------------------------------------------------------------- 1 | I know the Decorator Pattern therefore I RULE! -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/facade/Tuner.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.facade 2 | 3 | /** 4 | * 调音器 5 | */ 6 | class Tuner { 7 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/facade/CdPlayer.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.facade 2 | 3 | /** 4 | * CD 5 | */ 6 | class CdPlayer { 7 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/Clams.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 蛤蜊 5 | */ 6 | abstract class Clams -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/Cheese.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 奶酪 5 | */ 6 | abstract class Cheese { 7 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/Dough.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 面团 5 | */ 6 | abstract class Dough { 7 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/simple/CheesePizza.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.simple 2 | 3 | /** 4 | * 芝士比萨 5 | */ 6 | class CheesePizza : Pizza() { 7 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/simple/VeggiePizza.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.simple 2 | 3 | /** 4 | * 素比萨 5 | */ 6 | class VeggiePizza : Pizza() { 7 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/QuackBehavior.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.strategy 2 | 3 | /** 4 | * 鸭子的嘎嘎叫行为 5 | */ 6 | interface QuackBehavior { 7 | fun quack() 8 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/simple/PepperoniPizza.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.simple 2 | 3 | /** 4 | * 意大利辣香肠比萨 5 | */ 6 | class PepperoniPizza : Pizza() { 7 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/FlyBehavior.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.strategy 2 | 3 | /** 4 | * 鸭子的飞行行为 5 | * 所有飞行行为类必须实现的接口 6 | */ 7 | interface FlyBehavior { 8 | fun fly() 9 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/singleton/kotlin/KtSingletonEnum.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.singleton.kotlin 2 | 3 | /** 4 | * 枚举式单例 5 | */ 6 | enum class KtSingletonEnum { 7 | INSTANCE; 8 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/iterator/Menu.java: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.iterator; 2 | 3 | import java.util.Iterator; 4 | 5 | public interface Menu { 6 | 7 | Iterator createIterator(); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/adapter/duck/Duck.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.adapter.duck 2 | 3 | /** 4 | * 抽象鸭子 5 | */ 6 | interface Duck { 7 | 8 | fun quack() 9 | 10 | fun fly() 11 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/adapter/duck/Turkey.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.adapter.duck 2 | 3 | /** 4 | * 抽象火鸡🦃️ 5 | */ 6 | interface Turkey { 7 | 8 | fun gobble() 9 | 10 | fun fly() 11 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/decorator/coffee/CondimentDecorator.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.decorator.coffee 2 | 3 | /** 4 | * 调料 装饰者 抽象装饰者 5 | */ 6 | abstract class CondimentDecorator : Beverage() { 7 | 8 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/observer/DisplayElement.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.observer 2 | 3 | /** 4 | * 布告板的抽象接口 5 | */ 6 | interface DisplayElement { 7 | /** 8 | * 当布告板需要显示时,调用此方法 9 | */ 10 | fun display() 11 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/observer/ObserverPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 观察者模式 - Observer Pattern 2 | 3 | ## 概念 4 | 5 | 观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知,并自动更新 6 | 7 | ## 案例 8 | 9 | * 气象站应用 - 《Head First 设计模式》 10 | 当气象站的数据发生改变时,展示天气相关数据的布告板能够进行更新数据 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/Quack.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.strategy 2 | 3 | /** 4 | * 嘎嘎叫行为的实现 5 | */ 6 | class Quack : QuackBehavior { 7 | 8 | override fun quack() { 9 | println(" Quack. ") 10 | } 11 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/builder/classic/Product.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.builder.classic 2 | 3 | /** 4 | * 被构造的复杂对象 5 | */ 6 | class Product { 7 | 8 | var partOne: String = "" 9 | 10 | var partTwo: String = "" 11 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/FreshClams.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 新鲜蛤蜊 5 | */ 6 | class FreshClams : Clams() { 7 | init { 8 | println(" 生产出新鲜蛤蜊 FreshClams ") 9 | } 10 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/FrozenClams.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 冷冻蛤蜊 5 | */ 6 | class FrozenClams : Clams() { 7 | init { 8 | println(" 生产出冷冻蛤蜊 FrozenClams ") 9 | } 10 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/Squeak.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.strategy 2 | 3 | /** 4 | * 嘎嘎叫行为的实现类 5 | * 吱吱叫 6 | */ 7 | class Squeak : QuackBehavior { 8 | 9 | override fun quack() { 10 | println(" Squeak ") 11 | } 12 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/ThickCrustDough.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 厚皮面团 5 | */ 6 | class ThickCrustDough : Dough() { 7 | init { 8 | println(" 生产出厚皮面团 ThickCrustDough ") 9 | } 10 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/ThinCrustDough.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 薄皮面团 5 | */ 6 | class ThinCrustDough : Dough() { 7 | init { 8 | println(" 生产出薄皮面团 ThinCrustDough ") 9 | } 10 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/MuteQuack.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.strategy 2 | 3 | /** 4 | * 嘎嘎叫的实现类 5 | * 不会叫 安静的行为 6 | */ 7 | class MuteQuack : QuackBehavior { 8 | 9 | override fun quack() { 10 | println("<< Silence >>") 11 | } 12 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/builder/classic/Builder.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.builder.classic 2 | 3 | /** 4 | * 抽象接口 5 | */ 6 | interface Builder { 7 | 8 | fun buildPartOne() 9 | 10 | fun buildPartTwo() 11 | 12 | fun getProduct(): Product 13 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/observer/Observer.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.observer 2 | 3 | /** 4 | * 观察者接口 所有的观察者需要实现该接口 5 | */ 6 | interface Observer { 7 | /** 8 | * 更新方法 9 | */ 10 | fun update(temp: Float, humidity: Float, pressure: Float) 11 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/FlyNoWay.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.strategy 2 | 3 | /** 4 | * 飞行行为的实现 5 | * 给"不会"飞的鸭子用(包括橡皮鸭和诱饵鸭) 6 | */ 7 | class FlyNoWay : FlyBehavior { 8 | 9 | override fun fly() { 10 | println(" I can't fly. ") 11 | } 12 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/FlyWithWings.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.strategy 2 | 3 | /** 4 | * 飞行行为的实现 5 | * 给"真会"飞的鸭子用的 6 | */ 7 | class FlyWithWings : FlyBehavior { 8 | 9 | override fun fly() { 10 | println(" I'm flying. ") 11 | } 12 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/Command.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 命令接口 5 | */ 6 | interface Command { 7 | 8 | /** 9 | * 执行 10 | */ 11 | fun execute() 12 | 13 | /** 14 | * 撤销 15 | */ 16 | fun undo() 17 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/CreationalPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 创建型设计模式 2 | 3 | 这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活 4 | 5 | * 工厂方法模式(Factory Method Pattern) 6 | * 抽象工厂模式(Abstract Factory Pattern) 7 | * 单例模式(Singleton Pattern) 8 | * 建造者模式(Builder Pattern) 9 | * 原型模式(Prototype Pattern) -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/ShreddedMozzarellaCheese.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 意大利白干酪 5 | */ 6 | class ShreddedMozzarellaCheese : Cheese() { 7 | init { 8 | println(" 生产出意大利白干酪 ShreddedMozzarellaCheese ") 9 | } 10 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/FlyRocketPowered.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.strategy 2 | 3 | /** 4 | * 飞行行为的实现类 5 | * 利用火箭动力飞行的飞行行为 6 | */ 7 | class FlyRocketPowered : FlyBehavior { 8 | 9 | override fun fly() { 10 | println(" I'm flying with a rocket! ") 11 | } 12 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/GratedReggianoCheese.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 意大利reggiano高级干酪 5 | */ 6 | class GratedReggianoCheese : Cheese() { 7 | init { 8 | println(" 生产出意大利reggiano高级干酪 GratedReggianoCheese ") 9 | } 10 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/singleton/kotlin/KtSingleton.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.singleton.kotlin 2 | 3 | /** 4 | * 饿汉式 5 | * 饿汉模式在类加载的时候就对实例进行创建,实例在整个程序周期都存在 6 | * 它的好处是只在类加载的时候创建一次实例,不会存在多个线程创建多个实例的情况,避免了多线程同步的问题 7 | * 它的缺点也很明显,即使这个单例没有用到也会被创建,而且在类加载之后就被创建,内存就被浪费了 8 | */ 9 | object KtSingleton -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/StructuralPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 结构型设计模式 2 | 3 | 这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。 4 | 5 | * 组合模式(Composite Pattern) 6 | * 享元模式(Flyweight Pattern) 7 | * 代理模式(Proxy Pattern) 8 | * 桥接模式(Bridge Pattern) 9 | * 装饰器模式(Decorator Pattern) 10 | * 适配器模式(Adapter Pattern) 11 | * 外观模式(Facade Pattern) -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/facade/TheaterLights.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.facade 2 | 3 | /** 4 | * 剧场灯 5 | */ 6 | class TheaterLights { 7 | 8 | fun dim() { 9 | println("TheaterLights -> dim") 10 | } 11 | 12 | fun on() { 13 | println("TheaterLights -> on") 14 | } 15 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/adapter/duck/MallardDuck.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.adapter.duck 2 | 3 | /** 4 | * 绿头鸭 5 | */ 6 | class MallardDuck : Duck { 7 | override fun quack() { 8 | println("Quack") 9 | } 10 | 11 | override fun fly() { 12 | println("I`m flying") 13 | } 14 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/simple/SimpleFactoryPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 简单工厂模式 2 | 3 | ## 概念 4 | 5 | 工厂(factory)处理创建对象的细节 6 | 简单工厂其实不是一个设计模式,反而比较像是一种编程习惯。有些开发人员确实把这个编程习惯误认为是"工厂模式"(Factory Pattern) 7 | 利用静态方法定义一个简单的工厂,这是很常见的技巧,常被称为静态工厂,它的缺点也很明显,不能通过继承来改变创建方法的行为 8 | 9 | ## 案例 10 | 11 | * 比萨店 - 《Head First 设计模式》 12 | 对象村有一家披萨店,有很多风味的披萨 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/NoCommand.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 没有命令 5 | * 空对象模式 6 | */ 7 | class NoCommand : Command { 8 | 9 | override fun execute() { 10 | println(" no command ") 11 | } 12 | 13 | override fun undo() { 14 | println(" no command ") 15 | } 16 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/MacroCommand.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 宏命令 5 | * 用于执行一系列的命令 6 | */ 7 | class MacroCommand(private val commands: List) : Command { 8 | 9 | override fun execute() { 10 | commands.forEach { it.execute() } 11 | } 12 | 13 | override fun undo() {} 14 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/composite/Waitress.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.composite 2 | 3 | /** 4 | * 女招待 - 菜单的主要客户 5 | */ 6 | class Waitress(private val allMenus: MenuComponent) { 7 | 8 | /** 9 | * 女招待只需要调用最顶层菜单的print(),就可以打印整个菜单层次,包括所有菜单和菜单项 10 | */ 11 | fun printMenu() { 12 | allMenus.print() 13 | } 14 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/adapter/duck/WildTurkey.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.adapter.duck 2 | 3 | /** 4 | * 真实火鸡🦃️ 5 | */ 6 | class WildTurkey : Turkey { 7 | 8 | override fun gobble() { 9 | println("Gobble gobble") 10 | } 11 | 12 | override fun fly() { 13 | println("I`m flying a short distance") 14 | } 15 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/Light.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 电灯💡 5 | */ 6 | class Light { 7 | 8 | /** 9 | * 打开💡 10 | */ 11 | fun on() { 12 | println(" Light -> on ") 13 | } 14 | 15 | /** 16 | * 关闭💡 17 | */ 18 | fun off() { 19 | println(" Light -> off ") 20 | } 21 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/LightOnCommand.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 打开电灯的命令 5 | * 构造方法中需要传入某一个电灯💡以便让这个命令进行控制 6 | */ 7 | class LightOnCommand(private val light: Light) : Command { 8 | 9 | override fun execute() { 10 | light.on() 11 | } 12 | 13 | override fun undo() { 14 | light.off() 15 | } 16 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/iterator/Iterator.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.iterator 2 | 3 | /** 4 | * 一个迭代器接口大概会是这样的 或许使用Java提供的迭代器[java.util.Iterator]会更好 5 | */ 6 | interface Iterator { 7 | 8 | /** 9 | * 该方法会返回一个布尔值,表示是否还有下一个元素 10 | */ 11 | fun hasNext(): Boolean 12 | 13 | /** 14 | * 该方法会返回下一个元素 15 | */ 16 | fun next(): Any 17 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/facade/Screen.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.facade 2 | 3 | /** 4 | * 屏幕 5 | */ 6 | class Screen { 7 | 8 | /** 9 | * 放下大屏幕 10 | */ 11 | fun down() { 12 | println("Screen -> down") 13 | } 14 | 15 | /** 16 | * 拉起屏幕 17 | */ 18 | fun up() { 19 | println("Screen -> up") 20 | } 21 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/LightOffCommand.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 关闭电灯的命令 5 | * 构造方法中需要传入某一个电灯💡以便让这个命令进行控制 6 | */ 7 | class LightOffCommand(private val light: Light) : Command { 8 | 9 | override fun execute() { 10 | light.off() 11 | } 12 | 13 | override fun undo() { 14 | light.on() 15 | } 16 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/template/Tea.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.template 2 | 3 | /** 4 | * 茶🍵 5 | * 该类继承自[CaffeineBeverage],所以必须实现父类的抽象方法来完善步骤算法 6 | */ 7 | class Tea : CaffeineBeverage() { 8 | 9 | override fun brew() { 10 | println("Steeping the tea") 11 | } 12 | 13 | override fun addCondiments() { 14 | println("Adding Lemon") 15 | } 16 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/singleton/kotlin/KtSingletonStaticClass.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.singleton.kotlin 2 | 3 | /** 4 | * 静态内部类式 5 | */ 6 | class KtSingletonStaticClass { 7 | companion object { 8 | val instance = SingletonHolder.holder 9 | } 10 | 11 | private object SingletonHolder { 12 | val holder = KtSingletonStaticClass() 13 | } 14 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/ModelDuck.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.strategy 2 | 3 | /** 4 | * 模型鸭 5 | */ 6 | class ModelDuck : Duck() { 7 | init { 8 | // 一开始不会飞 9 | flyBehavior = FlyNoWay() 10 | // 会嘎嘎叫 11 | quackBehavior = Quack() 12 | } 13 | 14 | override fun display() { 15 | println(" I'm a model duck. ") 16 | } 17 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/StereoOffCommand.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 关闭音响命令 5 | * @property stereo Stereo 6 | * @constructor 7 | */ 8 | class StereoOffCommand(private val stereo: Stereo) : Command { 9 | 10 | override fun execute() { 11 | stereo.off() 12 | } 13 | 14 | override fun undo() { 15 | stereo.on() 16 | } 17 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/singleton/SingletonPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 单例模式 - Singleton Pattern 2 | 3 | ## 概念 4 | 5 | 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。 6 | 7 | ## 案例 8 | 9 | * Java 饿汉式单例 10 | * Java 线程安全懒汉式单例 11 | * Java 双重校验锁式单例 12 | * Java 静态内部类式单例 13 | * Java 枚举式单例 14 | * Kotlin 饿汉式单例 15 | * Kotlin 线程安全懒汉式单例 16 | * Kotlin 双重校验锁式单例 17 | * Kotlin 静态内部类式单例 18 | * Kotlin 枚举式单例 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/builder/classic/Director.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.builder.classic 2 | 3 | /** 4 | * Builder接口的构造者和使用者 5 | */ 6 | class Director(private val builder: Builder) { 7 | 8 | fun buildProduct() { 9 | builder.buildPartOne() 10 | builder.buildPartTwo() 11 | } 12 | 13 | fun getProduct(): Product { 14 | return builder.getProduct() 15 | } 16 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/decorator/coffee/DarkRoast.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.decorator.coffee 2 | 3 | /** 4 | * 深焙咖啡 具体组件 5 | */ 6 | class DarkRoast : Beverage() { 7 | 8 | override fun getDescription(): String { 9 | beverageDescription = "DarkRoast" 10 | return beverageDescription 11 | } 12 | 13 | override fun cost(): Double { 14 | return 0.99 15 | } 16 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/BehavioralPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 行为型设计模式 2 | 3 | 这些设计模式特别关注对象之间的通信。 4 | 5 | * 责任链模式(Chain of Responsibility Pattern) 6 | * 命令模式(Command Pattern) 7 | * 解释器模式(Interpreter Pattern) 8 | * 迭代器模式(Iterator Pattern) 9 | * 中介者模式(Mediator Pattern) 10 | * 备忘录模式(Memento Pattern) 11 | * 观察者模式(Observer Pattern) 12 | * 策略模式(Strategy Pattern) 13 | * 模板模式(Template Pattern) 14 | * 访问者模式(Visitor Pattern) 15 | * 状态模式(State Pattern) -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/StereoOnWithCDCommand.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 打开音响 5 | */ 6 | class StereoOnWithCDCommand(private val stereo: Stereo) : Command { 7 | 8 | override fun execute() { 9 | stereo.on() 10 | stereo.setCD() 11 | stereo.setVolume(11) 12 | } 13 | 14 | override fun undo() { 15 | stereo.off() 16 | } 17 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/MallardDuck.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.strategy 2 | 3 | /** 4 | * 绿头鸭 5 | * 具体的鸭子🦆 6 | */ 7 | class MallardDuck : Duck() { 8 | init { 9 | // 会飞 10 | flyBehavior = FlyWithWings() 11 | // 会嘎嘎叫 12 | quackBehavior = Quack() 13 | } 14 | 15 | override fun display() { 16 | println(" I'm a real Mallard duck. ") 17 | } 18 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/template/Coffee.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.template 2 | 3 | /** 4 | * 咖啡☕️ 5 | * 该类继承自[CaffeineBeverage],所以必须实现父类的抽象方法来完善步骤算法 6 | */ 7 | class Coffee : CaffeineBeverage() { 8 | 9 | override fun brew() { 10 | println("Dripping Coffee through filter") 11 | } 12 | 13 | override fun addCondiments() { 14 | println("Adding Sugar and Milk") 15 | } 16 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/iterator/MenuItem.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.iterator 2 | 3 | /** 4 | * 两位餐厅的厨师都同意实现这个类 5 | * 6 | * @property name String 名称 7 | * @property description String 叙述 8 | * @property vegetarian Boolean 是否为素菜 9 | * @property price Double 价格 10 | * @constructor 11 | */ 12 | class MenuItem constructor(val name: String, val description: String, val vegetarian: Boolean, val price: Double) -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/builder/classic/ConcreteBuilderA.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.builder.classic 2 | 3 | /** 4 | * Builder接口的具体实现 5 | */ 6 | class ConcreteBuilderA : Builder { 7 | 8 | private lateinit var product: Product 9 | 10 | override fun buildPartOne() {} 11 | 12 | override fun buildPartTwo() {} 13 | 14 | override fun getProduct(): Product { 15 | return product 16 | } 17 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/builder/classic/ConcreteBuilderB.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.builder.classic 2 | 3 | /** 4 | * Builder接口的具体实现 5 | */ 6 | class ConcreteBuilderB : Builder { 7 | 8 | private lateinit var product: Product 9 | 10 | override fun buildPartOne() {} 11 | 12 | override fun buildPartTwo() {} 13 | 14 | override fun getProduct(): Product { 15 | return product 16 | } 17 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/decorator/coffee/Beverage.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.decorator.coffee 2 | 3 | /** 4 | * 5 | * 饮料 抽象组件 6 | */ 7 | abstract class Beverage { 8 | 9 | /** 10 | * 饮料的描述 11 | */ 12 | var beverageDescription = "Unknown Beverage" 13 | 14 | 15 | abstract fun getDescription(): String 16 | 17 | /** 18 | * 成本 价钱 19 | */ 20 | abstract fun cost(): Double 21 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/observer/Subject.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.observer 2 | 3 | /** 4 | * 主题接口 被观察者需要实现该接口 5 | */ 6 | interface Subject { 7 | /** 8 | * 注册成为观察者 9 | */ 10 | fun registerObserver(o: Observer) 11 | 12 | /** 13 | * 移除观察者 14 | */ 15 | fun removeObserver(o: Observer) 16 | 17 | /** 18 | * 当主题状态改变时,该方法会被调用,以通知所有观察者 19 | */ 20 | fun notifyObservers() 21 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/state/State.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.state 2 | 3 | /** 4 | * 状态接口 5 | * 所有的状态都必须实现这个接口 6 | */ 7 | interface State { 8 | 9 | /** 10 | * 放入25美分 11 | */ 12 | fun insertQuarter() 13 | 14 | /** 15 | * 退回25美分 16 | */ 17 | fun ejectQuarter() 18 | 19 | /** 20 | * 转曲柄 21 | */ 22 | fun turnCrank() 23 | 24 | /** 25 | * 发放糖果 26 | */ 27 | fun dispense() 28 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/simple/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.simple 2 | 3 | /** 4 | * 简单工厂 比萨店 - 测试 5 | */ 6 | fun main() { 7 | val factory = SimplePizzaFactory() 8 | val store = PizzaStore(factory) 9 | store.orderPizza("cheese") 10 | // 输出结果 11 | // Pizza is being preparing... 12 | // Pizza is being baking... 13 | // Pizza is being cut... 14 | // Pizza is being box... 15 | // Pizza completed!!! 16 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/NYPizzaIngredientFactory.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 抽象工厂的具体工厂 5 | * 纽约风味的原料工厂 6 | * 对于原料家族的每一种原料,都提供了纽约风味 7 | */ 8 | class NYPizzaIngredientFactory : PizzaIngredientFactory { 9 | 10 | override fun createDough(): Dough = ThinCrustDough() 11 | 12 | override fun createCheese(): Cheese = GratedReggianoCheese() 13 | 14 | override fun createClam(): Clams = FreshClams() 15 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/CheesePizza.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 芝士比萨 5 | */ 6 | class CheesePizza(private val ingredientFactory: PizzaIngredientFactory) : Pizza() { 7 | 8 | override fun prepare() { 9 | println(" Preparing $name") 10 | dough = ingredientFactory.createDough() 11 | cheese = ingredientFactory.createCheese() 12 | clams = ingredientFactory.createClam() 13 | } 14 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/method/NYStyleCheesePizza.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.method 2 | 3 | /** 4 | * 纽约风味的芝士比萨 5 | */ 6 | class NYStyleCheesePizza : Pizza() { 7 | 8 | init { 9 | // 纽约比萨有自己的大蒜番茄酱和薄饼 10 | name = " NY style Sauce and Cheese Pizza " 11 | dough = " Thin Crust Dough " 12 | sauce = " Marinara Sauce " 13 | 14 | // 上面覆盖的是意大利reggiano高级干酪 15 | toppings.add("Grated Reggiano Cheese") 16 | } 17 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/ChicagoPizzaIngredientFactory.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 抽象工厂的具体工厂 5 | * 芝加哥风味的原料工厂 6 | * 对于原料家族的每一种原料,都提供了芝加哥风味 7 | */ 8 | class ChicagoPizzaIngredientFactory : PizzaIngredientFactory { 9 | 10 | override fun createDough(): Dough = ThickCrustDough() 11 | 12 | override fun createCheese(): Cheese = ShreddedMozzarellaCheese() 13 | 14 | override fun createClam(): Clams = FrozenClams() 15 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/composite/CompositePatternDoc.md: -------------------------------------------------------------------------------- 1 | # 组合模式 - Composite Pattern 2 | 3 | ## 概念 4 | 5 | 组合模式允许你将对象组合成树形结构来表现"整体/部分"层次结构。组合能让客户以一致的方式处理 个别对象以及对象组合 6 | 7 | ## 案例 8 | 9 | * 对象村餐厅和对象村煎饼屋合并后又在餐厅菜单中添加了饭后甜点菜单 - 《Head First 设计模式》 10 | 现有方式已经无法实现在餐厅菜单中又添加一个子菜单,所以我们使用了组合模式来解决这个问题 11 | 12 | # 知识点 13 | 14 | * 带子元素的元素称为节点(node),没有子元素的元素称为叶节点(leaf) 15 | * 组合包含组件。组件有两种:组合和叶节点元素。听起来像是递归,组合有一群孩子,这些孩子可以是别的组合或者叶节点元素。 16 | * 当你用这种方式组织数据的时候,最终会得到树形结构(正确的说法是由上而下的树形结构),根部是一个组合,而组合的分支逐渐往下延伸,直到叶节点为止。 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/decorator/coffee/Espresso.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.decorator.coffee 2 | 3 | /** 4 | * 浓缩咖啡 具体组件 5 | */ 6 | class Espresso : Beverage() { 7 | 8 | /** 9 | * 重写描述 10 | */ 11 | override fun getDescription(): String { 12 | beverageDescription = "Espresso" 13 | return beverageDescription 14 | } 15 | 16 | /** 17 | * 重写价格 18 | */ 19 | override fun cost(): Double { 20 | return 1.99 21 | } 22 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/PizzaIngredientFactory.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 抽象工厂定义了一个接口,所有的具体工厂都必须实现此接口,这个接口包含一组方法用来生产产品 5 | */ 6 | interface PizzaIngredientFactory { 7 | 8 | /** 9 | * 用于创建面团的抽象方法 10 | */ 11 | fun createDough(): Dough 12 | 13 | /** 14 | * 用于创建奶酪🧀️的抽象方法 15 | */ 16 | fun createCheese(): Cheese 17 | 18 | /** 19 | * 用于创建蛤蜊的抽象方法 20 | */ 21 | fun createClam(): Clams 22 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/decorator/coffee/HouseBlend.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.decorator.coffee 2 | 3 | /** 4 | * 综合咖啡 具体组件 5 | */ 6 | class HouseBlend : Beverage() { 7 | 8 | /** 9 | * 重写描述 10 | */ 11 | override fun getDescription(): String { 12 | beverageDescription = "HouseBlend" 13 | return beverageDescription 14 | } 15 | 16 | /** 17 | * 重写价格 18 | */ 19 | override fun cost(): Double { 20 | return 0.89 21 | } 22 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/StrategyPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 策略模式 - Strategy Pattern 2 | 3 | ## 概念 4 | 5 | 策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户 6 | 7 | ## 案例 8 | 9 | * 模拟鸭子应用 - 《Head First 设计模式》 10 | 模拟鸭子应用,应用中会出现各种鸭子,一边游泳,一边呱呱叫 11 | 12 | # 知识点 13 | 14 | * 定义一个算法家族,并让这些算法可以互换。正因为每一个算法都被封装起来了,所以客户可以轻易地使用不同的算法 15 | * 策略模式不是使用继承进行算法的实现,而是通过对象组合的方式,让客户可以选择算法的实现,更具有弹性。利用组合,客户就可以在运行时改变它们的算法,而客户需要做的,只是改用不同的策略对象 16 | * 一般来说,我们将策略模式想成是除了继承之外的一种弹性替代方案。如果你使用继承定义了一个类的行为,你将被这个行为困住,甚至要修改它都很难。有了策略模式,你可以通过组合不同的对象来改变行为 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/decorator/coffee/Soy.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.decorator.coffee 2 | 3 | /** 4 | * 豆浆 具体装饰者 5 | */ 6 | class Soy(private val beverage: Beverage) : CondimentDecorator() { 7 | 8 | /** 9 | * 修改描述 10 | */ 11 | override fun getDescription(): String { 12 | return "${beverage.getDescription()},Soy" 13 | } 14 | 15 | /** 16 | * 修改价格 17 | */ 18 | override fun cost(): Double { 19 | return 0.15 + beverage.cost() 20 | } 21 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/decorator/coffee/Milk.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.decorator.coffee 2 | 3 | /** 4 | * 牛奶调料 具体装饰者 5 | */ 6 | class Milk(private val beverage: Beverage) : CondimentDecorator() { 7 | 8 | /** 9 | * 修改描述 10 | */ 11 | override fun getDescription(): String { 12 | return "${beverage.getDescription()},Milk" 13 | } 14 | 15 | /** 16 | * 修改价格 17 | */ 18 | override fun cost(): Double { 19 | return 0.10 + beverage.cost() 20 | } 21 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/decorator/coffee/Mocha.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.decorator.coffee 2 | 3 | /** 4 | * 摩卡☕️ 具体装饰者 5 | */ 6 | class Mocha(private val beverage: Beverage) : CondimentDecorator() { 7 | 8 | /** 9 | * 修改描述 10 | */ 11 | override fun getDescription(): String { 12 | return "${beverage.getDescription()},Mocha" 13 | } 14 | 15 | /** 16 | * 修改价格 17 | */ 18 | override fun cost(): Double { 19 | return 0.20 + beverage.cost() 20 | } 21 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/facade/PopcornPopper.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.facade 2 | 3 | /** 4 | * 爆米花 5 | */ 6 | class PopcornPopper { 7 | 8 | /** 9 | * 打开爆米花机 10 | */ 11 | fun on() { 12 | println("PopcornPopper -> on") 13 | } 14 | 15 | /** 16 | * 爆出爆米花 17 | */ 18 | fun pop() { 19 | println("PopcornPopper -> pop") 20 | } 21 | 22 | /** 23 | * 关闭 24 | */ 25 | fun off() { 26 | println("PopcornPopper -> off") 27 | } 28 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/facade/Projector.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.facade 2 | 3 | /** 4 | * 投影机 5 | */ 6 | class Projector { 7 | 8 | /** 9 | * 打开投影机 10 | */ 11 | fun on() { 12 | println("Projector -> on") 13 | } 14 | 15 | /** 16 | * 宽屏模式 17 | */ 18 | fun wideScreenMode() { 19 | println("Projector -> wideScreenMode") 20 | } 21 | 22 | /** 23 | * 关闭 24 | */ 25 | fun off() { 26 | println("Projector -> off") 27 | } 28 | } -------------------------------------------------------------------------------- /DesignPattern.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/singleton/kotlin/KtSingletonLock.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.singleton.kotlin 2 | 3 | /** 4 | * 线程安全的懒汉式 5 | */ 6 | class KtSingletonLock { 7 | 8 | companion object { 9 | 10 | private var instance: KtSingletonLock? = null 11 | get() { 12 | if (field == null) field = KtSingletonLock() 13 | return field 14 | } 15 | 16 | @Synchronized 17 | fun instance(): KtSingletonLock { 18 | return instance!! 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/method/NYPizzaStore.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.method 2 | 3 | /** 4 | * 能够产生产品的类成为具体创建者 5 | * 纽约比萨店 加盟自对象村的比萨店 6 | */ 7 | class NYPizzaStore : PizzaStore() { 8 | 9 | /** 10 | * 这就是创建具体类的地方。对于每一种比萨类型,都是创建纽约风味。 11 | * 注意 超类的createPizza()方法并不知道正在创建哪一种比萨类型,它只知道这个比萨可以被准备、被烘烤、被切片、被装盒 12 | */ 13 | override fun createPizza(pizzaType: String): Pizza? { 14 | return when (pizzaType) { 15 | "cheese" -> NYStyleCheesePizza() 16 | else -> null 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/singleton/java/SingletonEnum.java: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.singleton.java; 2 | 3 | /** 4 | * 5.单例模式-枚举 5 | * 上面提到的四种实现单例的方式都有共同的缺点: 6 | * 1)需要额外的工作来实现序列化,否则每次反序列化一个序列化的对象时都会创建一个新的实例。 7 | * 2)可以使用反射强行调用私有构造器(如果要避免这种情况,可以修改构造器,让它在创建第二个实例的时候抛异常)。 8 | * 而枚举类很好的解决了这两个问题,使用枚举除了线程安全和防止反射调用构造器之外,还提供了自动序列化机制,防止反序列化的时候创建新的对象。 9 | * 因此,《Effective Java》作者推荐使用的方法。不过,在实际工作中,很少看见有人这么写。 10 | */ 11 | public enum SingletonEnum { 12 | INSTANCE; 13 | 14 | public SingletonEnum getInstance() { 15 | return INSTANCE; 16 | } 17 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/method/ChicagoPizzaStore.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.method 2 | 3 | /** 4 | * 能够产生产品的类成为具体创建者 5 | * 芝加哥比萨店 加盟自对象村的比萨店 6 | */ 7 | class ChicagoPizzaStore : PizzaStore() { 8 | 9 | /** 10 | * 这就是创建具体类的地方。对于每一种比萨类型,都是创建芝加哥风味。 11 | * 注意 超类的createPizza()方法并不知道正在创建哪一种比萨类型,它只知道这个比萨可以被准备、被烘烤、被切片、被装盒 12 | */ 13 | override fun createPizza(pizzaType: String): Pizza? { 14 | return when (pizzaType) { 15 | "cheese" -> ChicagoStyleCheesePizza() 16 | else -> null 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/observer/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.observer 2 | 3 | /** 4 | * 观察者模式 气象站-测试 5 | */ 6 | fun main() { 7 | // 创建被观察者 气象数据 8 | val weatherData = WeatherData() 9 | // 创建观察者 布告板 10 | val currentConditionsDisplay = CurrentConditionsDisplay(weatherData) 11 | 12 | // 模拟气象数据 13 | weatherData.setMeasurements(80F, 65F, 30.4F) 14 | weatherData.setMeasurements(82F, 70F, 29.2F) 15 | 16 | // 输出结果 17 | // Current conditions: 80.0F degrees and 65.0% humidity. 18 | // Current conditions: 82.0F degrees and 70.0% humidity. 19 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/SimpleRemoteControl.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 一个只有一个按钮和对应插槽的遥控器 5 | */ 6 | class SimpleRemoteControl { 7 | 8 | /** 9 | * 有一个插槽持有命令,而这个命令控制着一个装置 10 | */ 11 | private var slot: Command? = null 12 | 13 | /** 14 | * 这个方法用来设置插槽控制的命令。如果这段代码的客户想要改变遥控器按钮的行为,可以多次调用这个方法 15 | */ 16 | fun setCommand(command: Command) { 17 | slot = command 18 | } 19 | 20 | /** 21 | * 当按下按钮时,这个方法就会被调用,使得当前命令衔接插槽,并调用它的execute()方法 22 | */ 23 | fun buttonWasPressed() { 24 | slot?.execute() 25 | } 26 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/builder/BuilderPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 建造者模式 - Builder Pattern 2 | 3 | ## 概念 4 | 5 | 建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 6 | 7 | ## 案例 8 | 9 | * 经典的Builder模式 - 《Android高级进阶》 10 | * 变种的Builder模式(Java) 11 | 12 | ## 知识点 13 | 14 | * 经典的Builder模式主要有四个参与者 15 | * Product:被构造的复杂对象,ConcreteBuilder用来创建该对象的内部表示,并定义它的装配过程 16 | * Builder:抽象接口,用来定义创建Product对象的各个组成部件的操作 17 | * ConcreteBuilder:Builder接口的具体实现,可以定义多个,是实际构建Product对象的地方,同时会提供一个返回Product的接口 18 | * Director:Builder接口的构造者和使用者 19 | * 经典的Builder模式重点在于抽象出对象创建的步骤,并通过调用不同的具体实现从而得到不同的结果 20 | * 变种Builder模式的目的在于减少对象创建过程中引入的多个重载构造函数、可选参数以及setters过度使用导致的不必要的复杂性 21 | -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/adapter/duck/TurkeyAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.adapter.duck 2 | 3 | /** 4 | * 现在,假设你却鸭子对象,想用一些火鸡对象来冒充。显而易见,因为火鸡的接口不同,所以我们不能公然拿来用 5 | * 那么,就写个适配器吧 6 | * 首先,需要实现想转换成的类型接口,也就是你的客户所期望看到的接口 7 | * 接着,需要取得要适配的对象引用 8 | */ 9 | class TurkeyAdapter(private val turkey: Turkey) : Duck { 10 | 11 | /** 12 | * 鸭子嘎嘎叫的方法直接调用火鸡的咯咯叫 13 | */ 14 | override fun quack() { 15 | turkey.gobble() 16 | } 17 | 18 | /** 19 | * 火鸡的飞行距离很短,要让鸭子的飞行和火鸡的飞行能够对应起来,必须连续五次调用火鸡的fly()来完成 20 | */ 21 | override fun fly() { 22 | (1..5).forEach { _ -> turkey.fly() } 23 | } 24 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/AbstractFactoryPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 抽象工厂模式 - Abstract Factory Pattern 2 | 3 | ## 概念 4 | 5 | 抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。 6 | 7 | ## 案例 8 | 9 | * 针对于比萨店的原料工厂 - 《Head First 设计模式》 10 | 对象村有一家披萨店,有很多风味的披萨,并且对外开放加盟,加盟店可以拥有自己的特点,另外还提供了针对不同地域的原料提供商 11 | 12 | ## 知识点 13 | 14 | * 抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么,这样一来,客户就从具体的产品中被解耦 15 | * 抽象工厂定义了一个接口,所有的具体工厂都必须实现此接口 16 | * 每个具体工厂都能够生产一整组的产品,对于这个产品家族,每一个具体工厂都有不同的实现 17 | * 抽象工厂经常以工厂方法的方式实现。抽象工厂的任务是定一个负责创建一组产品的接口。这个接口内的每个方法都负责创建一个具体产品,同时我们利用实现抽象工厂的子类来提供这些具体的做法。所以,在抽象工厂中利用工厂方法实现生产方法是相当自然的做法。 18 | * 抽象工厂使用的方法是对象的组合 19 | * 工厂是很有威力的技巧,帮助我们针对抽象编程,而不是针对具体类编程 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/state/StatePatternDoc.md: -------------------------------------------------------------------------------- 1 | # 状态模式 - State Pattern 2 | 3 | ## 概念 4 | 5 | 状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类 6 | 7 | ## 案例 8 | 9 | * 糖果机 - 《Head First 设计模式》 10 | 11 | # 知识点 12 | 13 | * 这个模式将状态封装成独立的类,并将动作委托到代表当前状态的类,行为会随着内部状态而改变 14 | * State接口定义了一个所有具体状态的共同接口;任何状态都实现这个相同的接口,这样一来,状态之间可以互相替换 15 | * 以状态模式而言,我们将一群行为封装在状态对象中,context的行为随时可委托到那些状态对象中的一个。随着时间的流逝,当前状态在状态对象集合之间游走改变,以反映出context内部的状态,因此,context的行为也会跟着改变。但是context的客户对于状态对象了解不多,甚至根本是浑然不觉 16 | * 我们把状态模式想成是不用在context中放置许多条件判断的替代方案。通过将行为包装进状态对象中,你可以通过在context内简单地改变状态对象来改变context的行为 17 | * 状态模式和策略模式有着相同的类图,但是它们的意图不同 18 | * 通过将每个状态封装近一个类,我们把以后需要做的任何改变局部化了 19 | * 使用状态模式通常会导致设计中类的数目大量增加 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/simple/SimplePizzaFactory.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.simple 2 | 3 | /** 4 | * 简单工厂 5 | * 封装了所有比萨创建对象的代码,它只做一件事,就是为它的客户创建比萨 6 | * 该类应该是应用中唯一用到具体披萨类的地方 7 | */ 8 | class SimplePizzaFactory { 9 | 10 | /** 11 | * 所有客户通过此方法来创建比萨对象 12 | * @param pizzaType String 比萨类型 13 | * @return Pizza 14 | */ 15 | fun createPizza(pizzaType: String): Pizza? { 16 | return when (pizzaType) { 17 | "cheese" -> CheesePizza() 18 | "pepperoni" -> PepperoniPizza() 19 | "veggie" -> VeggiePizza() 20 | else -> null 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/Stereo.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 音响 5 | */ 6 | class Stereo { 7 | 8 | /** 9 | * 打开 10 | */ 11 | fun on() { 12 | println(" Stereo -> on ") 13 | } 14 | 15 | /** 16 | * 设置CD 17 | */ 18 | fun setCD() { 19 | println(" Stereo -> set CD ") 20 | } 21 | 22 | /** 23 | * 设置音量 24 | * @param int Int 音量 25 | */ 26 | fun setVolume(int: Int) { 27 | println(" Stereo -> set volume $int ") 28 | } 29 | 30 | /** 31 | * 关闭 32 | */ 33 | fun off() { 34 | println(" Stereo -> off ") 35 | } 36 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/template/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.template 2 | 3 | /** 4 | * 测试模板方法模式 - 冲泡咖啡和茶 5 | */ 6 | fun main() { 7 | val tea = Tea() 8 | val coffee = Coffee() 9 | 10 | println("Making tea...") 11 | tea.prepareRecipe() 12 | 13 | println("\nMaking coffee...") 14 | coffee.prepareRecipe() 15 | // 输出结果 16 | // Making tea... 17 | // Boiling water 18 | // Steeping the tea 19 | // Pouring into cup 20 | // Adding Lemon 21 | // 22 | // Making coffee... 23 | // Boiling water 24 | // Dripping Coffee through filter 25 | // Pouring into cup 26 | // Adding Sugar and Milk 27 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/singleton/java/SingletonLock.java: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.singleton.java; 2 | 3 | /** 4 | * 2.单例模式-懒汉式-线程同步锁 5 | * 懒汉模式中单例是在需要的时候才去创建的,如果单例已经创建,再次调用获取接口将不会重新创建新的对象,而是直接返回之前创建的对象。 6 | * 并且加锁保证了线程同步问题。 7 | * 如果某个单例使用的次数少,并且创建单例消耗的资源较多,那么就需要实现单例的按需创建,这个时候使用懒汉模式就是一个不错的选择。 8 | */ 9 | public class SingletonLock { 10 | private static SingletonLock instance = null; 11 | 12 | private SingletonLock() { 13 | } 14 | 15 | public static synchronized SingletonLock newInstance() { 16 | if (null == instance) { 17 | instance = new SingletonLock(); 18 | } 19 | return instance; 20 | } 21 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/state/SoldOutState.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.state 2 | 3 | /** 4 | * 售罄状态 5 | */ 6 | class SoldOutState constructor(private val gumballMachine: GumballMachine) : State { 7 | 8 | override fun insertQuarter() { 9 | println("You can't insert a quarter, the machine is sold out") 10 | } 11 | 12 | override fun ejectQuarter() { 13 | println("You can't eject, you haven't inserted a quarter yet") 14 | } 15 | 16 | override fun turnCrank() { 17 | println("You turned, but there are no gumballs") 18 | } 19 | 20 | override fun dispense() { 21 | println("No gumball dispensed") 22 | } 23 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/builder/variant1/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.builder.variant1 2 | 3 | /** 4 | * 测试变种Builder模式 5 | */ 6 | fun main() { 7 | val user1 = User.Builder("Yunshuo", "Qu") 8 | .age(22) 9 | .gender("男") 10 | .phoneNo("10086") 11 | .builder() 12 | 13 | val user2 = User.Builder("小红", "张") 14 | .age(18) 15 | .gender("女") 16 | .builder() 17 | println(user1.toString()) 18 | println(user2.toString()) 19 | // 输出结果 20 | // User{mFirstName='Yunshuo', mLastName='Qu', mGender='男', mAge=22, mPhoneNo='10086'} 21 | // User{mFirstName='小红', mLastName='张', mGender='女', mAge=18, mPhoneNo='null'} 22 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/method/ChicagoStyleCheesePizza.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.method 2 | 3 | /** 4 | * 芝加哥风味的芝士比萨 5 | */ 6 | class ChicagoStyleCheesePizza : Pizza() { 7 | 8 | init { 9 | // 芝加哥比萨使用小番茄酱作为酱料,并使用厚饼 10 | name = " Chicago Style Deep Dish Cheese Pizza " 11 | dough = " Extra Thick Crust Dough " 12 | sauce = " Plum Tomato Sauce " 13 | 14 | // 芝加哥风味的深盘比萨使用许多mozzarella(意大利白干酪) 15 | toppings.add("Shredded Mozzarella Cheese ") 16 | } 17 | 18 | /** 19 | * 这个芝加哥风味比萨覆盖了cut()方法,将比萨切成正方形 20 | */ 21 | override fun cut() { 22 | println(" Cutting the pizza into square slices ") 23 | } 24 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/method/FactoryMethodPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 工厂方法模式 - Factory Method Pattern 2 | 3 | ## 概念 4 | 5 | 所有的工厂模式都用来封装对象的创建。工厂方法模式(Factory Method Pattern)通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的 6 | 这样,客户程序中关于超类的代码就和子类对象创建代码解耦了 抽象的Creator提供了一个创建对象的方法的接口,也称为"工厂方法" 7 | ,在抽象的Creator中,任何其他实现的方法,都可能使用到这个工厂方法所制造出来的产品,但只有子类真正实现这个工厂方法并创建产品 8 | 9 | ## 案例 10 | 11 | * 比萨店 - 《Head First 设计模式》 12 | 对象村有一家披萨店,有很多风味的披萨,并且对外开放加盟,加盟店可以拥有自己的特点 13 | 14 | ## 知识点 15 | 16 | * 将创建对象的代码集中在一个对象或方法中,可以避免代码中的重复,并且更方便以后的维护。这也意味着客户在实例化对象时,只会依赖于接口,而不是具体类,这可以帮助我们针对接口编程,而不针对实现编程。这让代码更具有弹性,可以应对未来的扩展。 17 | * 工厂方法使用的方法是继承,把对象的创建委托给子类,子类实现工厂方法来创建对象 18 | * 利用工厂方法创建对象,需要扩展一个类,并覆盖它的工厂方法 19 | * 工厂方法允许类将实例化延迟到子类进行 20 | * 工厂方法是创建一个框架,让子类决定要如何实现。 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/simple/PizzaStore.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.simple 2 | 3 | /** 4 | * 对象村的比萨店 5 | * 工厂的客户,该类现在通过[SimplePizzaFactory]取得比萨的实例 6 | */ 7 | class PizzaStore(private val factory: SimplePizzaFactory) { 8 | 9 | /** 10 | * 订购比萨 11 | * @param pizzaType String 订购的比萨类型 12 | * @return Pizza 13 | */ 14 | fun orderPizza(pizzaType: String): Pizza? { 15 | // 将创建比萨的过程替换成工厂对象的创建方法,这里不再使用具体的实例化,不再依赖具体的披萨类型 16 | val pizza = factory.createPizza(pizzaType) 17 | return pizza?.apply { 18 | prepare() 19 | bake() 20 | cut() 21 | box() 22 | completed() 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/singleton/java/Singleton.java: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.singleton.java; 2 | 3 | /** 4 | * 1.单例模式-饿汉式 5 | * 从代码中我们看到,类的构造函数定义为private的,保证其他类不能实例化此类,然后提供了一个静态实例并返回给调用者。 6 | * 饿汉模式是最简单的一种实现方式,饿汉模式在类加载的时候就对实例进行创建,实例在整个程序周期都存在。 7 | * 它的好处是只在类加载的时候创建一次实例,不会存在多个线程创建多个实例的情况,避免了多线程同步的问题。 8 | * 它的缺点也很明显,即使这个单例没有用到也会被创建,而且在类加载之后就被创建,内存就被浪费了。 9 | * 这种实现方式适合单例占用内存比较小,在初始化时就会被用到的情况。 10 | * 但是,如果单例占用的内存比较大,或单例只是在某个特定场景下才会用到,使用饿汉模式就不合适了,这时候就需要用到懒汉模式进行延迟加载。 11 | */ 12 | public class Singleton { 13 | 14 | private static Singleton instance = new Singleton(); 15 | 16 | private Singleton() { 17 | } 18 | 19 | public static Singleton newInstance() { 20 | return instance; 21 | } 22 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/singleton/java/SingletonStaticClass.java: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.singleton.java; 2 | 3 | /** 4 | * 4.单例模式-静态内部类 5 | * 这种方式同样利用了类加载机制来保证只创建一个instance实例。 6 | * 它与饿汉模式一样,也是利用了类加载机制,因此不存在多线程并发的问题。 7 | * 不一样的是,它是在内部类里面去创建对象实例。 8 | * 这样的话,只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载。 9 | * 也就是说这种方式可以同时保证延迟加载和线程安全。 10 | */ 11 | public class SingletonStaticClass { 12 | 13 | private static class SingletonHolder { 14 | public static SingletonStaticClass instance = new SingletonStaticClass(); 15 | } 16 | 17 | private SingletonStaticClass() { 18 | } 19 | 20 | public static SingletonStaticClass newInstance() { 21 | return SingletonHolder.instance; 22 | } 23 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/CommandPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 命令模式 - Command Pattern 2 | 3 | ## 概念 4 | 5 | 命令模式将"请求"封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操纵 6 | 7 | ## 案例 8 | 9 | * 家电自动化遥控器 - 《Head First 设计模式》 10 | 通过遥控器可以控制一些家电 11 | 12 | ## 知识点 13 | 14 | * 一个命令对象通过在特定接收者上绑定一组动作来封装一个请求。要达到这一点,命令对象将动作和接收者包进对象中。这个对象只暴露出一个execute() 15 | 方法,当此方法被调用的时候,接收者就会进行这些动作。从外面来看,其他对象不知道究竟哪个接收者进行了哪些动作,只知道如果调用execute()方法,请求的目的就能够达到。 16 | * 命令模式将发出请求的对象和执行请求的对象解耦 17 | * 在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组对象 18 | * 调用者可以接收命令当作参数,甚至在运行时动态地进行 19 | * 命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态 20 | * 宏命令是命令的一种简单的延伸,允许调用多个命令。宏方法也可以支持撤销 21 | * 命令可以将运算块打包(一个接收者和一组动作),然后将它传来传去,就像是一般的对象一样。现在,即使在命令对象被创建许久之后,运算依然可以被调用。事实上,它甚至可以在不同的线程中被调用。我们可以利用这样的特性衍生出一些应用,例如:日程安排、线程池、工作队列等。 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/facade/DvdPlayer.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.facade 2 | 3 | /** 4 | * DVD 5 | */ 6 | class DvdPlayer { 7 | 8 | /** 9 | * 打开DVD 10 | */ 11 | fun on() { 12 | println("DvdPlayer -> on") 13 | } 14 | 15 | /** 16 | * 播放DVD 17 | */ 18 | fun play() { 19 | println("DvdPlayer -> play") 20 | } 21 | 22 | /** 23 | * 暂停DVD 24 | */ 25 | fun stop() { 26 | println("DvdPlayer -> stop") 27 | } 28 | 29 | /** 30 | * 弹出DVD 31 | */ 32 | fun eject() { 33 | println("DvdPlayer -> eject") 34 | } 35 | 36 | /** 37 | * 关闭 38 | */ 39 | fun off() { 40 | println("DvdPlayer -> off") 41 | } 42 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/state/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.state 2 | 3 | /** 4 | * 测试策略模式下的糖果机 5 | */ 6 | fun main() { 7 | val gumballMachine = GumballMachine(10) 8 | 9 | gumballMachine.insertQuarter() 10 | gumballMachine.turnCrank() 11 | 12 | gumballMachine.insertQuarter() 13 | gumballMachine.turnCrank() 14 | gumballMachine.insertQuarter() 15 | gumballMachine.turnCrank() 16 | // 输出结果 17 | // You inserted a quarter 18 | // You turned... 19 | // A gumball comes rolling out the slot... 20 | // You inserted a quarter 21 | // You turned... 22 | // A gumball comes rolling out the slot... 23 | // You inserted a quarter 24 | // You turned... 25 | // A gumball comes rolling out the slot... 26 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/observer/CurrentConditionsDisplay.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.observer 2 | 3 | /** 4 | * 目前状况布告板 5 | */ 6 | class CurrentConditionsDisplay(weatherData: Subject) : Observer, DisplayElement { 7 | init { 8 | // 注册成为观察者 9 | weatherData.registerObserver(this) 10 | } 11 | 12 | private var temperature: Float = 0F 13 | 14 | private var humidity: Float = 0F 15 | 16 | override fun display() { 17 | println(" Current conditions: ${temperature}F degrees and ${humidity}% humidity. ") 18 | } 19 | 20 | override fun update(temp: Float, humidity: Float, pressure: Float) { 21 | // 取到自己需要的数据 22 | this.temperature = temp 23 | this.humidity = humidity 24 | display() 25 | } 26 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/decorator/io/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.decorator.io 2 | 3 | import java.io.* 4 | 5 | /** 6 | * 装饰者模式 Java I/O 自定义LowerCaseInputStream-测试 7 | */ 8 | fun main() { 9 | var read: Int 10 | try { 11 | val inputStream: InputStream = 12 | LowerCaseInputStream(BufferedInputStream(FileInputStream("/Users/quyunshuo/Projects/IdeaProjects/DesignPattern/src/com/quyunshuo/designpattern/structural/decorator/io/test.txt"))) 13 | while (inputStream.read().also { read = it } != -1) { 14 | print(read.toChar()) 15 | } 16 | inputStream.close() 17 | } catch (e: IOException) { 18 | e.printStackTrace() 19 | } 20 | // 输出结果 21 | // i know the decorator pattern therefore i rule! 22 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/CeilingFanLowCommand.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 打开吊扇低速的命令 5 | */ 6 | class CeilingFanLowCommand(private val ceilingFan: CeilingFan) : Command { 7 | 8 | /** 9 | * 增加局部状态以便追踪吊扇之前的速度 10 | */ 11 | private var prevSpeed = 0 12 | 13 | override fun execute() { 14 | // 改变风扇的速度之前需要先将它之前的状态记录起来,以便撤销时使用 15 | prevSpeed = ceilingFan.getSpeed() 16 | ceilingFan.low() 17 | } 18 | 19 | override fun undo() { 20 | when (prevSpeed) { 21 | CeilingFan.OFF -> ceilingFan.off() 22 | CeilingFan.LOW -> ceilingFan.low() 23 | CeilingFan.MEDIUM -> ceilingFan.medium() 24 | CeilingFan.HIGH -> ceilingFan.high() 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/CeilingFanOffCommand.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 关闭吊扇的命令 5 | */ 6 | class CeilingFanOffCommand(private val ceilingFan: CeilingFan) : Command { 7 | 8 | /** 9 | * 增加局部状态以便追踪吊扇之前的速度 10 | */ 11 | private var prevSpeed = 0 12 | 13 | override fun execute() { 14 | // 改变风扇的速度之前需要先将它之前的状态记录起来,以便撤销时使用 15 | prevSpeed = ceilingFan.getSpeed() 16 | ceilingFan.off() 17 | } 18 | 19 | override fun undo() { 20 | when (prevSpeed) { 21 | CeilingFan.OFF -> ceilingFan.off() 22 | CeilingFan.LOW -> ceilingFan.low() 23 | CeilingFan.MEDIUM -> ceilingFan.medium() 24 | CeilingFan.HIGH -> ceilingFan.high() 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/CeilingFanHighCommand.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 打开吊扇最高转速的命令 5 | */ 6 | class CeilingFanHighCommand(private val ceilingFan: CeilingFan) : Command { 7 | 8 | /** 9 | * 增加局部状态以便追踪吊扇之前的速度 10 | */ 11 | private var prevSpeed = 0 12 | 13 | override fun execute() { 14 | // 改变风扇的速度之前需要先将它之前的状态记录起来,以便撤销时使用 15 | prevSpeed = ceilingFan.getSpeed() 16 | ceilingFan.high() 17 | } 18 | 19 | override fun undo() { 20 | when (prevSpeed) { 21 | CeilingFan.OFF -> ceilingFan.off() 22 | CeilingFan.LOW -> ceilingFan.low() 23 | CeilingFan.MEDIUM -> ceilingFan.medium() 24 | CeilingFan.HIGH -> ceilingFan.high() 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/CeilingFanMediumCommand.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 打开吊扇中速的命令 5 | */ 6 | class CeilingFanMediumCommand(private val ceilingFan: CeilingFan) : Command { 7 | 8 | /** 9 | * 增加局部状态以便追踪吊扇之前的速度 10 | */ 11 | private var prevSpeed = 0 12 | 13 | override fun execute() { 14 | // 改变风扇的速度之前需要先将它之前的状态记录起来,以便撤销时使用 15 | prevSpeed = ceilingFan.getSpeed() 16 | ceilingFan.medium() 17 | } 18 | 19 | override fun undo() { 20 | when (prevSpeed) { 21 | CeilingFan.OFF -> ceilingFan.off() 22 | CeilingFan.LOW -> ceilingFan.low() 23 | CeilingFan.MEDIUM -> ceilingFan.medium() 24 | CeilingFan.HIGH -> ceilingFan.high() 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/facade/Amplifier.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.facade 2 | 3 | /** 4 | * 功放 5 | */ 6 | class Amplifier { 7 | 8 | /** 9 | * 打开功放 10 | */ 11 | fun on() { 12 | println("Amplifier -> on") 13 | } 14 | 15 | /** 16 | * 设置DVD 17 | */ 18 | fun setDvd() { 19 | println("Amplifier -> setDvd") 20 | } 21 | 22 | /** 23 | * 设置环绕声 24 | */ 25 | fun setSurroundSound() { 26 | println("Amplifier -> setSurroundSound") 27 | } 28 | 29 | /** 30 | * 设定音量 31 | */ 32 | fun setVolume(volume: Int) { 33 | println("Amplifier -> setVolume $volume") 34 | } 35 | 36 | /** 37 | * 关闭 38 | */ 39 | fun off() { 40 | println("Amplifier -> off") 41 | } 42 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/adapter/AdapterPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 适配器模式 - Adapter Pattern 2 | 3 | ## 概念 4 | 5 | 适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原本不兼容的类可以合作无间 6 | 7 | ## 案例 8 | 9 | * 伪装成鸭子的火鸡 - 《Head First 设计模式》 10 | * 兼容Java早期集合枚举器的集合迭代器 - 《Head First 设计模式》 11 | 12 | ## 知识点 13 | 14 | * 客户和被适配者是解耦的,一个不知道另一个 15 | * 客户使用适配器的过程: 16 | * 客户通过目标接口调用适配器的方法对适配器发出请求 17 | * 适配器使用适配器接口把请求转换成被适配者的一个或多个调用接口 18 | * 客户接收到调用的结果,但并未察觉这一切是适配器在起转换作用 19 | * 这个模式可以通过创建适配器进行接口转换,让不兼容的接口变成兼容。这可以让客户从实现的接口解耦。如果一段时间后,我们想要改变接口,适配器就可以将改变的部分封装起来,客户就不必为了应对不同的接口而每次跟着修改 20 | * 这个设计模式充满着良好的OO设计原则:使用对象组合、以修改的接口包装被适配者:这种做法还有额外的优点,那就是,被适配者的任何子类,都可以搭配着适配器使用 21 | * 这个模式是如何把客户和接口绑定起来,而不是和实现绑定起来的。我们可以使用数个适配器,每一个都负责转换不同组的后台类。或者,也可以加上新的实现,只要它们遵守目标接口就可以 22 | * 实际上有"两种"适配器:"对象"适配器和"类"适配器,,类适配器需要多重继承才能够实现,这在Java中是不可能的。 23 | * 当需要使用一个现有的类而其接口并不符合你的需要时,就使用适配器 24 | * 实现一个适配器可能需要一番功夫,也可能不费工夫,视目标接口的大小与复杂度而定 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/composite/MenuItem.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.composite 2 | 3 | /** 4 | * 菜单项,这是组合类图里的叶类,它实现组合内元素的行为 5 | * 扩展自组件[MenuComponent] 6 | */ 7 | class MenuItem( 8 | private val itemName: String, 9 | private val itemDescription: String, 10 | private val itemIsVegetarian: Boolean, 11 | private val itemPrice: Double 12 | ) : MenuComponent() { 13 | 14 | override fun getName(): String = itemName 15 | 16 | override fun getDescription(): String = itemDescription 17 | 18 | override fun getPrice(): Double = itemPrice 19 | 20 | override fun isVegetarian(): Boolean = itemIsVegetarian 21 | 22 | override fun print() { 23 | print(" $itemName") 24 | if (itemIsVegetarian) print("(v)") 25 | println(", ${getPrice()}") 26 | println(" -- ${getDescription()}") 27 | } 28 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/simple/Pizza.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.simple 2 | 3 | /** 4 | * 工厂的"产品",比萨🍕 5 | * 该类是抽象的,具有一些有用的实现,这些实现也可以被覆盖 6 | */ 7 | abstract class Pizza { 8 | 9 | /** 10 | * 比萨的准备过程 11 | */ 12 | open fun prepare() { 13 | println(" Pizza is being preparing... ") 14 | } 15 | 16 | /** 17 | * 比萨的烘烤过程 18 | */ 19 | open fun bake() { 20 | println(" Pizza is being baking... ") 21 | } 22 | 23 | /** 24 | * 比萨的裁切过程 25 | */ 26 | open fun cut() { 27 | println(" Pizza is being cut... ") 28 | } 29 | 30 | /** 31 | * 比萨的包装过程 32 | */ 33 | open fun box() { 34 | println(" Pizza is being box... ") 35 | } 36 | 37 | /** 38 | * 制作完成 39 | */ 40 | open fun completed() { 41 | println(" Pizza completed!!! ") 42 | } 43 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/decorator/io/LowerCaseInputStream.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.decorator.io 2 | 3 | import java.io.FilterInputStream 4 | import java.io.InputStream 5 | 6 | /** 7 | * 利用Java I/O 典型的装饰者模式 8 | * 新的输入装饰者 把输入流中的所有大写字符转成小写 9 | * 10 | * 首先扩展[java.io.FilterInputStream],这是所有InputStream的抽象装饰者 11 | */ 12 | class LowerCaseInputStream(input: InputStream) : FilterInputStream(input) { 13 | 14 | override fun read(): Int { 15 | val read = super.read() 16 | // 将字符转为大写 17 | return if (read == -1) read else Character.toLowerCase(read.toChar()).toInt() 18 | } 19 | 20 | override fun read(b: ByteArray, off: Int, len: Int): Int { 21 | val read = super.read(b, off, len) 22 | (off until off + read).forEach { 23 | b[it] = Character.toLowerCase(read.toChar()).toByte() 24 | } 25 | return read 26 | } 27 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.strategy 2 | 3 | /** 4 | * 策略模式 模拟鸭子应用-测试 5 | */ 6 | fun main() { 7 | testMallardDuck() 8 | testModelDuck() 9 | } 10 | 11 | /** 12 | * 绿头鸭测试 13 | */ 14 | fun testMallardDuck() { 15 | val mallardDuck = MallardDuck() 16 | mallardDuck.performFly() 17 | mallardDuck.performQuack() 18 | mallardDuck.display() 19 | mallardDuck.swim() 20 | // 输出结果 21 | // I'm flying. 22 | // Quack. 23 | // I'm a real Mallard duck. 24 | // All ducks float, even decoys! 25 | } 26 | 27 | /** 28 | * 模型鸭测试 29 | */ 30 | fun testModelDuck() { 31 | val modelDuck = ModelDuck() 32 | modelDuck.performFly() 33 | // 重新设定飞行行为 34 | modelDuck.setDuckFlyBehavior(FlyRocketPowered()) 35 | modelDuck.performFly() 36 | // 输出结果 37 | // I can't fly. 38 | // I'm flying with a rocket! 39 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/CeilingFan.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 吊扇 5 | */ 6 | class CeilingFan(private val location: String) { 7 | 8 | private var speed = OFF 9 | 10 | companion object { 11 | 12 | const val HIGH = 3 13 | 14 | const val MEDIUM = 2 15 | 16 | const val LOW = 1 17 | 18 | const val OFF = 0 19 | } 20 | 21 | fun high() { 22 | speed = HIGH 23 | println(" CeilingFan - HIGH ") 24 | } 25 | 26 | fun medium() { 27 | speed = MEDIUM 28 | println(" CeilingFan - MEDIUM ") 29 | } 30 | 31 | fun low() { 32 | speed = LOW 33 | println(" CeilingFan - LOW ") 34 | } 35 | 36 | fun off() { 37 | speed = OFF 38 | println(" CeilingFan - OFF ") 39 | } 40 | 41 | fun getSpeed(): Int { 42 | return speed 43 | } 44 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/NYPizzaStore.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 能够产生产品的类成为具体创建者 5 | * 纽约比萨店 加盟自对象村的比萨店 6 | */ 7 | class NYPizzaStore : PizzaStore() { 8 | 9 | /** 10 | * 这就是创建具体类的地方。对于每一种比萨类型,都是创建纽约风味。 11 | * 注意 超类的createPizza()方法并不知道正在创建哪一种比萨类型,它只知道这个比萨可以被准备、被烘烤、被切片、被装盒 12 | */ 13 | override fun createPizza(pizzaType: String): Pizza? { 14 | return when (pizzaType) { 15 | "cheese" -> { 16 | // 纽约店会用到纽约比萨原料工厂 17 | // 由该原料工厂生产所有纽约风味比萨所需要的原料 18 | val nyPizzaIngredientFactory = NYPizzaIngredientFactory() 19 | // 把工厂传递给每一个比萨,以便比萨能从工厂中获取原料 20 | CheesePizza(nyPizzaIngredientFactory).apply { 21 | name = " New York Style Cheese Pizza " 22 | } 23 | } 24 | else -> null 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/decorator/DecoratorPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 装饰者模式 - Decorator Pattern 2 | 3 | ## 概念 4 | 5 | 装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案 6 | 7 | ## 案例 8 | 9 | * 星巴兹咖啡应用 - 《Head First 设计模式》 10 | 星巴兹咖啡店是一家专注做咖啡的门店,里面有各式各样的咖啡以及调料 11 | 12 | * Java I/O - JDK 13 | java.io包内的I/O相关类使用了装饰者模式 14 | 15 | ## 知识点 16 | 17 | * 利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态的进行扩展 18 | * 通过动态地组合对象,可以写新的代码添加新功能,而无须修改现有代码。既然没有改变现有代码,那么引进bug或产生意外副作用的机会将大幅度减少 19 | * 装饰者和被装饰对象拥有相同地超类型 20 | * 可以用一个或多个装饰者包装一个对象 21 | * 既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它 22 | * 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的 23 | * 继承Beverage抽象类,是为了有正确的类型,而不是继承它的行为。行为来自装饰者和基础组件,或与其他装饰者之间的组合关系 24 | * 通常装饰者模式是采用抽象类,但在Java中可以使用接口 25 | * Java I/O 也引出装饰者模式的一个"缺点":利用装饰者模式,常常造成设计中有大量的小类,数量实在太多,可能会造成使用此API程序员的困扰 26 | * 采用装饰者在实例化组件时,将增加代码的复杂度,一旦使用装饰者模式,不只需要实例化组件,还要把此组件包装进装饰者中 27 | * 继承属于扩展形式之一,但不见得是达到弹性设计的最佳方式 28 | * 组合和委托可用于在运行时动态地加上新的行为 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/method/PizzaStore.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.method 2 | 3 | /** 4 | * 这是抽象创建者类,它定义了一个抽象的工厂方法,让子类实现此方法制造产品 5 | * 创建者通常会包含依赖于抽象产品的代码,而这些抽象产品由子类制造。创建者不需要真的知道在哪制造哪种具体产品 6 | * 比萨店类 7 | */ 8 | abstract class PizzaStore { 9 | 10 | /** 11 | * 订购比萨 12 | * @param pizzaType String 订购的比萨类型 13 | * @return Pizza 14 | */ 15 | fun orderPizza(pizzaType: String): Pizza? { 16 | // 将创建比萨的过程替换成工厂对象的创建方法,这里不再使用具体的实例化,不再依赖具体的披萨类型 17 | val pizza = createPizza(pizzaType) 18 | return pizza?.apply { 19 | prepare() 20 | bake() 21 | cut() 22 | box() 23 | } 24 | } 25 | 26 | /** 27 | * 工厂方法是抽象的,所以依赖子类来处理对象的创建 28 | * 工厂方法必须返回一个产品。超类中定义的方法通常使用到工厂方法的返回值 29 | * 工厂方法将客户(也就是超类中的代码,例如[orderPizza]和实际创建具体产品的代码分隔开来) 30 | */ 31 | protected abstract fun createPizza(pizzaType: String): Pizza? 32 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/PizzaStore.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 这是抽象创建者类,它定义了一个抽象的工厂方法,让子类实现此方法制造产品 5 | * 创建者通常会包含依赖于抽象产品的代码,而这些抽象产品由子类制造。创建者不需要真的知道在哪制造哪种具体产品 6 | * 比萨店类 7 | */ 8 | abstract class PizzaStore { 9 | 10 | /** 11 | * 订购比萨 12 | * @param pizzaType String 订购的比萨类型 13 | * @return Pizza 14 | */ 15 | fun orderPizza(pizzaType: String): Pizza? { 16 | // 将创建比萨的过程替换成工厂对象的创建方法,这里不再使用具体的实例化,不再依赖具体的披萨类型 17 | val pizza = createPizza(pizzaType) 18 | return pizza?.apply { 19 | prepare() 20 | bake() 21 | cut() 22 | box() 23 | } 24 | } 25 | 26 | /** 27 | * 工厂方法是抽象的,所以依赖子类来处理对象的创建 28 | * 工厂方法必须返回一个产品。超类中定义的方法通常使用到工厂方法的返回值 29 | * 工厂方法将客户(也就是超类中的代码,例如[orderPizza]和实际创建具体产品的代码分隔开来) 30 | */ 31 | protected abstract fun createPizza(pizzaType: String): Pizza? 32 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/ChicagoPizzaStore.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 能够产生产品的类成为具体创建者 5 | * 芝加哥比萨店 加盟自对象村的比萨店 6 | */ 7 | class ChicagoPizzaStore : PizzaStore() { 8 | 9 | /** 10 | * 这就是创建具体类的地方。对于每一种比萨类型,都是创建芝加哥风味。 11 | * 注意 超类的createPizza()方法并不知道正在创建哪一种比萨类型,它只知道这个比萨可以被准备、被烘烤、被切片、被装盒 12 | */ 13 | override fun createPizza(pizzaType: String): Pizza? { 14 | return when (pizzaType) { 15 | "cheese" -> { 16 | // 芝加哥店会用到芝加哥比萨原料工厂 17 | // 由该原料工厂生产所有芝加哥风味比萨所需要的原料 18 | val chicagoPizzaIngredientFactory = ChicagoPizzaIngredientFactory() 19 | // 把工厂传递给每一个比萨,以便比萨能从工厂中获取原料 20 | CheesePizza(chicagoPizzaIngredientFactory).apply { 21 | name = " Chicago Style Cheese Pizza " 22 | } 23 | } 24 | else -> null 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/state/NoQuarterState.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.state 2 | 3 | /** 4 | * 没有25美分状态 5 | */ 6 | class NoQuarterState constructor(private val gumballMachine: GumballMachine) : State { 7 | 8 | /** 9 | * 如果有人投入了25美分,我们就打印出一条消息说我们接受了25美分,然后改变糖果机的状态到[HasQuarterState] 10 | */ 11 | override fun insertQuarter() { 12 | println("You inserted a quarter") 13 | gumballMachine.setState(gumballMachine.mHasQuarterState) 14 | } 15 | 16 | /** 17 | * 当前的状态是没有25美分 所以当想要取出25美分时 是绝对不行的🙅 18 | */ 19 | override fun ejectQuarter() { 20 | println("You haven`t inserted a quarter") 21 | } 22 | 23 | /** 24 | * 当前是没有25美分状态 所以不能要求糖果🍬 25 | */ 26 | override fun turnCrank() { 27 | println("You turned,but there`s no quarter") 28 | } 29 | 30 | /** 31 | * 现在是没有25美分的状态 所以不能发放糖果 32 | */ 33 | override fun dispense() { 34 | println("You need to pay first") 35 | } 36 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/strategy/Duck.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.strategy 2 | 3 | /** 4 | * 抽象鸭子类 5 | */ 6 | abstract class Duck { 7 | 8 | var flyBehavior: FlyBehavior? = null 9 | 10 | var quackBehavior: QuackBehavior? = null 11 | 12 | /** 13 | * 鸭子外观 14 | */ 15 | abstract fun display() 16 | 17 | /** 18 | * 委托给行为类 19 | */ 20 | fun performFly() { 21 | flyBehavior?.fly() 22 | } 23 | 24 | /** 25 | * 委托给行为类 26 | */ 27 | fun performQuack() { 28 | quackBehavior?.quack() 29 | } 30 | 31 | /** 32 | * 设定鸭子的飞行行为 33 | */ 34 | fun setDuckFlyBehavior(fb: FlyBehavior) { 35 | flyBehavior = fb 36 | } 37 | 38 | /** 39 | * 设定鸭子的嘎嘎叫行为 40 | */ 41 | fun setDuckQuackBehavior(qb: QuackBehavior) { 42 | quackBehavior = qb 43 | } 44 | 45 | /** 46 | * 游泳 47 | */ 48 | fun swim() { 49 | println(" All ducks float, even decoys! ") 50 | } 51 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/state/SoldState.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.state 2 | 3 | /** 4 | * 售出状态 5 | */ 6 | class SoldState constructor(private val gumballMachine: GumballMachine) : State { 7 | 8 | override fun insertQuarter() { 9 | println("Please wait, we`re already giving you a gumball") 10 | } 11 | 12 | override fun ejectQuarter() { 13 | println("Sorry, you already turned the crank") 14 | } 15 | 16 | override fun turnCrank() { 17 | println("Turning twice doesn`t get you another gumball!") 18 | } 19 | 20 | override fun dispense() { 21 | // 首先需要让机器发放糖果 22 | gumballMachine.releaseBall() 23 | // 然后我们需要判断糖果机剩余的糖果,然后将糖果机的状态转换至对应的状态 24 | if (gumballMachine.count > 0) { 25 | gumballMachine.setState(gumballMachine.mNoQuarterState) 26 | } else { 27 | println("Oops, out of gumballs!") 28 | gumballMachine.setState(gumballMachine.mSoldOutState) 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/facade/FacadePatternDoc.md: -------------------------------------------------------------------------------- 1 | # 外观模式 - Facade Pattern 2 | 3 | ## 概念 4 | 5 | 外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。 6 | 7 | ## 案例 8 | 9 | * 家庭影院 - 《Head First 设计模式》 10 | 11 | ## 知识点 12 | 13 | * 外观模式允许我们让客户和子系统之间避免紧耦合 14 | * 我们在设计中,不要让太多的类耦合在一起,免得修改系统中一部分,会影响到其它部分。如果许多类之间相互依赖,那么这个系统就会变成一个易碎的系统,它需要花很多成本维护,也许会因为太复杂而不易被其他人了解。 15 | * 有了外观模式,通过实现一个提供更合理的接口的外观类,可以将一个复杂的子系统变得容易使用。如果你需要复杂子系统的强大威力,别担心,还是可以使用原来的复杂接口的;但如果你需要的是一个方便使用的接口,那就使用外观 16 | * 外观没有"封装"子系统的类,外观只提供简化的接口。所以客户如果觉得有必要,依然可以直接使用子系统的类,这是外观模式一个很好的特征:提供简化接口的同时,依然将系统完整的功能暴露出来,以供需要的人使用 17 | * 可以为一个子系统创建许多个外观。 18 | * 适配器模式将一个或多个类接口变成客户所期望的一个接口。虽然大多数教科书所采用的例子中适配器只适配一个类,但是你可以适配很多类来提供一个接口让客户端编码。类似地,一个外观也可以只针对一个拥有复杂接口的类提供简化的接口。两种模式的差异,不在于它们包装了几个类,而是在于它们的意图。适配器模式的意图是:" 19 | 改变"接口并符合客户的期望;而外观模式的意图是,提供子系统的一个简化接口 20 | * 外观模式不止简化了接口,也将客户从组件的子系统中解耦 21 | * 外观和适配器模式都可以包装许多类,但是外观模式的意图是简化接口,而适配器的意图是将接口转换成不同接口 22 | * 当需要简化并统一一个很大的接口或者一群负责的接口时,使用外观 23 | * 实现一个外观,需要将子系统组合进外观中,然后将工作委托给子系统执行 24 | * 适配器将一个对象包装起来改变其接口;装饰者将一个对象包装起来以增加新的行为和责任;而外观将一群对象"包装"起来以简化其接口 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/iterator/IteratorPatternDoc.md: -------------------------------------------------------------------------------- 1 | # 迭代器模式 - Iterator Pattern 2 | 3 | ## 概念 4 | 5 | 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示 6 | 7 | ## 案例 8 | 9 | * 对象村餐厅和对象村煎饼屋合并新招的女招待 - 《Head First 设计模式》 10 | 两个餐厅使用的不同的聚合数据结构,所以无法合并菜单,新招来了一个女招待负责合并后餐厅的服务,我们需要解决的就是如何让两个不同数据结构的菜单一起工作。 11 | 12 | # 知识点 13 | 14 | * 迭代器模式让我们能游走于聚合内的每一个元素,而又不暴露其内部的表示。把游走的任务放在了迭代器上,而不是聚合上。这样简化了聚合的接口和实现,也让责任各得其所。 15 | * 迭代器模式依赖于一个名为迭代器的接口,一旦我们有了这个接口,就可以为各种对象集合实现迭代器:数组、列表、散列表... 16 | * 当我们说"集合"(collection)的时候,我们指的是一群对象。其存储方式可以是各式各样的数据结构。例如:列表、数组、散列表,无论用什么方式存储,一律可以视为是集合,有的时候也被成为聚合(aggregate)。 17 | * 对于散列表这样的集合,元素之间并没有明显的次序关系,我们该怎么办? 18 | * 迭代器意味着没有次序。只是取出所有的元素,并不表示取出元素的先后就代表元素的大小次序。对于迭代器来说,数据结构可以是有次序的,或是没有次序的,甚至数据可以是重复的。除非某个集合的文件有特别说明,否则不可以对迭代器所取出的元素大小顺序作出假设。 19 | 20 | # 设计原则 21 | 22 | * 单一职责 23 | 一个类应该只有一个引起变化的原因 24 | 类的每个责任都有改变的潜在区域。超过一个责任就意味着超过一个改变的区域。 25 | 26 | * 内聚(cohesion) 27 | 内聚这个术语用来度量一个类或模块紧密地达到单一目的和责任。 28 | 当一个模块或一个类被设计成只支持一组相关的功能时,我们说它具有高内聚;反之,当被设计成支持一组不相关的功能时,我们说它具有低内聚。 29 | 内聚是一个比单一职责原则更普遍的概念,但两者其实关系是很密切的。遵守这个原则的类容易具有很高的凝聚力,而且比背负许多责任的低内聚类更容易维护。 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/decorator/coffee/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.decorator.coffee 2 | 3 | /** 4 | * 装饰者模式 星巴兹咖啡应用-测试 5 | */ 6 | fun main() { 7 | // 订一杯 Espresso(浓缩咖啡),不需要调料,打印出它的描述与价格 8 | val beverage: Beverage = Espresso() 9 | println("${beverage.getDescription()} \$${beverage.cost()}") 10 | // 输出结果 11 | // Espresso $1.99 12 | 13 | 14 | // 订一杯 DarkRoast(深焙咖啡),加双份摩卡,加一份牛奶,打印出它的描述与价格 15 | var beverage2: Beverage = DarkRoast() 16 | // 使用装饰者摩卡 对深焙咖啡进行装饰 17 | beverage2 = Mocha(beverage2) 18 | // 第二份摩卡 19 | beverage2 = Mocha(beverage2) 20 | println("${beverage2.getDescription()} \$${beverage2.cost()}") 21 | // 输出结果 22 | // DarkRoast,Mocha,Mocha $1.39 23 | 24 | 25 | // 再来一杯调料为牛奶、豆浆、摩卡的HouseBlend(综合咖啡) 26 | var beverage3: Beverage = HouseBlend() 27 | beverage3 = Milk(beverage3) 28 | beverage3 = Soy(beverage3) 29 | beverage3 = Mocha(beverage3) 30 | println("${beverage3.getDescription()} \$${beverage3.cost()}") 31 | // 输出结果 32 | // HouseBlend,Milk,Soy,Mocha $1.3399999999999999 33 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/Pizza.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 产品类 对[PizzaStore]创建者来说,产品就是[Pizza] 5 | * 抽象比萨🍕,所有的具体比萨都必须派生自这个类 6 | */ 7 | abstract class Pizza { 8 | 9 | /** 10 | * 比萨名称 11 | */ 12 | var name = "" 13 | 14 | /** 15 | * 比萨面团类型 16 | */ 17 | lateinit var dough: Dough 18 | 19 | /** 20 | * 比萨蛤蜊类型 21 | */ 22 | lateinit var clams: Clams 23 | 24 | /** 25 | * 比萨奶酪类型 26 | */ 27 | lateinit var cheese: Cheese 28 | 29 | /** 30 | * 比萨的准备过程 31 | * 该方法声明为抽象,在这个方法中,我们需要收集比萨所需要的原料,而这些原料来自于原料工厂 32 | */ 33 | abstract fun prepare() 34 | 35 | /** 36 | * 比萨的烘烤过程 37 | */ 38 | open fun bake() { 39 | println(" Bake for 25 minutes at 350 ") 40 | } 41 | 42 | /** 43 | * 比萨的裁切过程 44 | */ 45 | open fun cut() { 46 | println(" Cutting the pizza into diagonal slices ") 47 | } 48 | 49 | /** 50 | * 比萨的包装过程 51 | */ 52 | open fun box() { 53 | println(" Place pizza in official PizzaStore box ") 54 | } 55 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/iterator/Waitress.java: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.iterator; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | 6 | /** 7 | * 女招待 8 | */ 9 | public class Waitress { 10 | 11 | ArrayList menus; 12 | 13 | public Waitress(ArrayList menus) { 14 | this.menus = menus; 15 | } 16 | 17 | public void printMenu() { 18 | Iterator menuIterator = menus.iterator(); 19 | while (menuIterator.hasNext()) { 20 | Menu menu = (Menu) menuIterator.next(); 21 | // 使用菜单项获取到对应菜单的迭代器 22 | printMenu(menu.createIterator()); 23 | } 24 | } 25 | 26 | /** 27 | * 使用迭代器打印输出元素 28 | * 29 | * @param iterator 菜单项的迭代器 30 | */ 31 | void printMenu(Iterator iterator) { 32 | while (iterator.hasNext()) { 33 | MenuItem menuItem = (MenuItem) iterator.next(); 34 | System.out.print(menuItem.getName() + ", "); 35 | System.out.print(menuItem.getPrice() + " -- "); 36 | System.out.println(menuItem.getDescription()); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/adapter/iterator/EnumerationIterator.java: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.adapter.iterator; 2 | 3 | import java.util.Enumeration; 4 | import java.util.Iterator; 5 | 6 | /** 7 | * 在Java中早期的集合类型,都实现了一个名为 elements() 的方法,该方法会返回一个 Enumeration (枚举)类 8 | * 这个 Enumeration 接口可以逐一走过此集合的元素,而无需知道它们在集合中是如何被管理的 9 | * 当 sun 推出更新后的集合类时,开始使用了 Iterator (迭代器),这个接口和枚举接口很像,都可以让你遍历此集合类型内的每个元素 10 | * 但不同的是,迭代器还提供了删除元素的能力 11 | * 而今天...我们经常面对遗留代码,这些代码暴露出枚举器接口,但我们又希望在新的代码中只使用迭代器。如是我们就写了一个适配器来转换 12 | */ 13 | public class EnumerationIterator implements Iterator { 14 | 15 | private final Enumeration enumeration; 16 | 17 | public EnumerationIterator(Enumeration enumeration) { 18 | this.enumeration = enumeration; 19 | } 20 | 21 | @Override 22 | public boolean hasNext() { 23 | return enumeration.hasMoreElements(); 24 | } 25 | 26 | @Override 27 | public E next() { 28 | return enumeration.nextElement(); 29 | } 30 | 31 | /** 32 | * 很不幸,我们不能支持迭代器的remove()方法,所以必须放弃。在这里,我们的做法是抛出一个异常 33 | */ 34 | @Override 35 | public void remove() { 36 | throw new UnsupportedOperationException(); 37 | } 38 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/adapter/duck/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.adapter.duck 2 | 3 | /** 4 | * 测试一下我们的适配器 5 | */ 6 | fun main() { 7 | val duck = MallardDuck() 8 | val turkey = WildTurkey() 9 | val adapter = TurkeyAdapter(turkey) 10 | 11 | println("The Turkey says...") 12 | turkey.gobble() 13 | turkey.fly() 14 | 15 | println("\nThe Duck says...") 16 | testDuck(duck) 17 | 18 | println("\nThe TurkeyAdapter says...") 19 | testDuck(adapter) 20 | // 输出结果 21 | // The Turkey says... 22 | // Gobble gobble 23 | // I`m flying a short distance 24 | // 25 | // The Duck says... 26 | // Quack 27 | // I`m flying 28 | // 29 | // The TurkeyAdapter says... 30 | // Gobble gobble 31 | // I`m flying a short distance 32 | // I`m flying a short distance 33 | // I`m flying a short distance 34 | // I`m flying a short distance 35 | // I`m flying a short distance 36 | 37 | // 我们让本来不相同的两个接口使用适配器变得"相同",通过适配器来转换火鸡的行为使其让客户感觉不到其实这个鸭子是个火鸡 38 | // 火鸡是被适配者 客户和被适配者是解耦的 39 | } 40 | 41 | /** 42 | * 取得一只鸭子并调用它的方法 43 | * @param duck Duck 44 | */ 45 | fun testDuck(duck: Duck) { 46 | duck.quack() 47 | duck.fly() 48 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/template/TemplatePatternDoc.md: -------------------------------------------------------------------------------- 1 | # 模板方法模式 - Template Pattern 2 | 3 | ## 概念 4 | 5 | 模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到了子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。 6 | 7 | ## 案例 8 | 9 | * 星巴兹咖啡师傅训练手册 - 《Head First 设计模式》 10 | 使用模板模式封装咖啡和茶的冲泡步骤算法 原始的训练手册 11 | * 星巴兹咖啡冲泡法 12 | * 把水煮沸 13 | * 用沸水冲泡咖啡 14 | * 把咖啡倒进杯子 15 | * 加糖的牛奶 16 | * 星巴兹茶冲泡法 17 | * 把水煮沸 18 | * 用沸水浸泡茶叶 19 | * 把茶倒进杯子 20 | * 加柠檬 21 | 22 | # 知识点 23 | 24 | * 我们也可以有"默认不做事的方法",我们称这个方法为"hook"(钩子🪝)。子类可以视情况决定要不要覆盖它们。 25 | * 钩子是一种被声明在抽象类中的方法,但只有空的或默认的实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩。要不要挂钩,由子类自行决定。 26 | * 创建一个模板方法时,怎么才知道什么时候该使用抽象方法,什么时候使用钩子? 27 | * 当子类"必须"提供算法中的某个方法或步骤的实现时,就使用抽象方法。 28 | * 如果算法的这个部分是可选的,就使用钩子。如果是钩子的话,子类可以选择实现这个钩子,但并不强制这么做。 29 | * 使用钩子真正的目的是什么? 30 | * 钩子有几种用法。钩子可以让子类实现算法中可选的部分,或者在钩子对于子类的实现并不重要的时候,子类可以对钩子置之不理。 31 | * 钩子的另一个用法,是让子类能够有机会对模板方法中某些即将发生的(或刚刚发生的)步骤作出反应。 32 | * 钩子也可以让子类有能力为其抽象类作一些决定。 33 | * 子类必须实现抽象类中的所有方法吗? 34 | * 使得,每一个具体的子类都必须定义所有的抽象方法,并为模板方法算法中未定义步骤提供完整的实现。 35 | * 似乎我应该保持抽象方法的数目越少越好,否则,在子类中实现这些方法将会很麻烦 36 | * 当你在写模板方法的时候,心里要随时记得这一点。想要做到这一点,可以让算法内的步骤不要切割得太细,但是如果步骤太少的话,会比较没有弹性,所以要使情况折衷。 37 | * 也请记住,某些步骤是可选的,所以你可以将这些步骤实现成钩子,而不是实现成抽象方法,这样可以让抽象类的子类的负荷减轻。 38 | * -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/state/HasQuarterState.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.state 2 | 3 | import kotlin.random.Random 4 | 5 | /** 6 | * 有25美分状态 7 | */ 8 | class HasQuarterState constructor(private val gumballMachine: GumballMachine) : State { 9 | 10 | /** 11 | * 有25美分的时候不应该再放入25美分了 12 | */ 13 | override fun insertQuarter() { 14 | println("You can`t insert another quarter") 15 | } 16 | 17 | /** 18 | * 退出顾客的25美分,并将状态设置为[NoQuarterState] 19 | */ 20 | override fun ejectQuarter() { 21 | println("Quarter returned") 22 | gumballMachine.setState(gumballMachine.mNoQuarterState) 23 | } 24 | 25 | /** 26 | * 当曲柄被转动时,我们将状态设置为[SoldState] 27 | */ 28 | override fun turnCrank() { 29 | println("You turned...") 30 | val nextInt = Random.nextInt(0, 10) 31 | if (nextInt == 0 && gumballMachine.count > 1) { 32 | gumballMachine.setState(gumballMachine.mWinnerState) 33 | } else { 34 | gumballMachine.setState(gumballMachine.mSoldState) 35 | } 36 | } 37 | 38 | /** 39 | * 该状态下不能直接请求发放糖果 应该先转动曲柄 40 | */ 41 | override fun dispense() { 42 | println("No gumball dispensed") 43 | } 44 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/abstract/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.abstract 2 | 3 | /** 4 | * 抽象工厂模式 比萨商店-测试 5 | */ 6 | fun main() { 7 | 8 | val nyPizzaStore = NYPizzaStore() 9 | val chicagoPizzaStore = ChicagoPizzaStore() 10 | 11 | val nyCheesePizza = nyPizzaStore.orderPizza("cheese") 12 | println(" Ethan ordered a ${nyCheesePizza?.name} \n") 13 | 14 | val chicagoPizza = chicagoPizzaStore.orderPizza("cheese") 15 | println(" Joel ordered a ${chicagoPizza?.name} ") 16 | 17 | // 输出结果 18 | // Preparing New York Style Cheese Pizza 19 | // 生产出薄皮面团 ThinCrustDough 20 | // 生产出意大利reggiano高级干酪 GratedReggianoCheese 21 | // 生产出新鲜蛤蜊 FreshClams 22 | // Bake for 25 minutes at 350 23 | // Cutting the pizza into diagonal slices 24 | // Place pizza in official PizzaStore box 25 | // Ethan ordered a New York Style Cheese Pizza 26 | // 27 | // Preparing Chicago Style Cheese Pizza 28 | // 生产出厚皮面团 ThickCrustDough 29 | // 生产出意大利白干酪 ShreddedMozzarellaCheese 30 | // 生产出冷冻蛤蜊 FrozenClams 31 | // Bake for 25 minutes at 350 32 | // Cutting the pizza into diagonal slices 33 | // Place pizza in official PizzaStore box 34 | // Joel ordered a Chicago Style Cheese Pizza 35 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/method/Pizza.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.method 2 | 3 | /** 4 | * 产品类 对[PizzaStore]创建者来说,产品就是[Pizza] 5 | * 抽象比萨🍕,所有的具体比萨都必须派生自这个类 6 | */ 7 | abstract class Pizza { 8 | 9 | /** 10 | * 比萨名称 11 | */ 12 | var name = "" 13 | 14 | /** 15 | * 比萨面团类型 16 | */ 17 | var dough = "" 18 | 19 | /** 20 | * 比萨酱料类型 21 | */ 22 | var sauce = "" 23 | 24 | val toppings = mutableListOf() 25 | 26 | /** 27 | * 比萨的准备过程 28 | */ 29 | open fun prepare() { 30 | println(" Preparing $name ") 31 | println(" Tossing dough... ") 32 | println(" Adding sauce... ") 33 | println(" Adding toppings: ") 34 | toppings.forEach { 35 | println(" $it ") 36 | } 37 | } 38 | 39 | /** 40 | * 比萨的烘烤过程 41 | */ 42 | open fun bake() { 43 | println(" Bake for 25 minutes at 350 ") 44 | } 45 | 46 | /** 47 | * 比萨的裁切过程 48 | */ 49 | open fun cut() { 50 | println(" Cutting the pizza into diagonal slices ") 51 | } 52 | 53 | /** 54 | * 比萨的包装过程 55 | */ 56 | open fun box() { 57 | println(" Place pizza in official PizzaStore box ") 58 | } 59 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/state/WinnerState.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.state 2 | 3 | /** 4 | * 赢家状态 5 | * 糖果机🍬有一个活动 当曲柄被转动时,有10%的机率出来的是两颗糖果🍬(多送一颗) 6 | */ 7 | class WinnerState constructor(private val gumballMachine: GumballMachine) : State { 8 | 9 | override fun insertQuarter() { 10 | println("Please wait, we're already giving you a Gumball") 11 | } 12 | 13 | override fun ejectQuarter() { 14 | println("Please wait, we're already giving you a Gumball") 15 | } 16 | 17 | override fun turnCrank() { 18 | println("Turning again doesn't get you another gumball!") 19 | } 20 | 21 | override fun dispense() { 22 | gumballMachine.releaseBall() 23 | if (gumballMachine.count == 0) { 24 | gumballMachine.setState(gumballMachine.mSoldOutState) 25 | } else { 26 | gumballMachine.releaseBall() 27 | println("YOU'RE A WINNER! You got two gumballs for your quarter") 28 | if (gumballMachine.count > 0) { 29 | gumballMachine.setState(gumballMachine.mNoQuarterState) 30 | } else { 31 | println("Oops, out of gumballs!") 32 | gumballMachine.setState(gumballMachine.mSoldOutState) 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/composite/Menu.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.composite 2 | 3 | /** 4 | * 组合类 - 菜单 5 | * 菜单和菜单项一样,都扩展自[MenuComponent] 6 | */ 7 | class Menu(private val menuName: String, private val menuDescription: String) : MenuComponent() { 8 | 9 | /** 10 | * 菜单可以有任意数的孩子,这些孩子必须属于[MenuComponent]类型,我们使用ArrayList记录它们 11 | */ 12 | private val menuComponents = ArrayList() 13 | 14 | override fun add(menuComponent: MenuComponent) { 15 | menuComponents.add(menuComponent) 16 | } 17 | 18 | override fun remove(menuComponent: MenuComponent) { 19 | menuComponent.remove(menuComponent) 20 | } 21 | 22 | override fun getChild(i: Int): MenuComponent = menuComponents[i] 23 | 24 | override fun getName(): String = menuName 25 | 26 | override fun getDescription(): String = menuDescription 27 | 28 | /** 29 | * 该方法不仅打印出菜单本身的信息,也打印出菜单内所有组件的内容:其他菜单和菜单项 30 | */ 31 | override fun print() { 32 | print("\n${getName()}") 33 | println(", ${getDescription()}") 34 | println("------------------------") 35 | 36 | // 使用迭代器遍历所有菜单组件 37 | val iterator = menuComponents.iterator() 38 | while (iterator.hasNext()) { 39 | val menuComponent = iterator.next() 40 | menuComponent.print() 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/iterator/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.iterator 2 | 3 | import java.util.ArrayList 4 | 5 | /** 6 | * 测试女招待-迭代器模式 7 | */ 8 | fun main() { 9 | // 煎饼屋菜单 10 | val pancakeHouseMenu = PancakeHouseMenu() 11 | // 餐厅菜单 12 | val dinerMenu = DinerMenu() 13 | // 将两个菜单聚合 14 | val menus = ArrayList() 15 | menus.add(pancakeHouseMenu) 16 | menus.add(dinerMenu) 17 | // 女招待进行输出所有的菜单项 18 | val waitress = Waitress(menus) 19 | waitress.printMenu() 20 | // 输出结果 21 | // K&B's Pancake Breakfast, 2.99 -- Pancakes with scrambled eggs and toast 22 | // Regular Pancake Breakfast, 2.99 -- Pancakes with fried eggs, sausage 23 | // Blueberry Pancakes, 3.49 -- Pancakes made with fresh blueberries and blueberry syrup 24 | // Waffles, 3.59 -- Waffles with your choice of blueberries or strawberries 25 | // Vegetarian BLT, 2.99 -- (Fakin') Bacon with lettuce & tomato on whole wheat 26 | // BLT, 2.99 -- Bacon with lettuce & tomato on whole wheat 27 | // Soup of the day, 3.29 -- Soup of the day, with a side of potato salad 28 | // Hotdog, 3.05 -- A hot dog, with sauerkraut, relish, onions, topped with cheese 29 | // Steamed Veggies and Brown Rice, 3.99 -- Steamed vegetables over brown rice 30 | // Pasta, 3.89 -- Spaghetti with Marinara Sauce, and a slice of sourdough bread 31 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/template/CaffeineBeverage.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.template 2 | 3 | /** 4 | * 咖啡因饮料抽象类 5 | * 茶和咖啡都有咖啡因 6 | * 它被声明为抽象,用来作为基类,其子类必须实现其操作 7 | */ 8 | abstract class CaffeineBeverage { 9 | 10 | /** 11 | * 此方法定义了处理茶🍵和咖啡☕️的步骤算法 12 | * 不将此方法设置为open是因为我们不希望子类覆盖这个方法 13 | * 这就是模板方法,该方法定义了一连串的步骤,每个步骤由一个方法代表 14 | */ 15 | fun prepareRecipe() { 16 | boilWater() 17 | brew() 18 | pourInCup() 19 | // 使用hook方法customerWantsCondiments()来控制是否添加调味品 20 | if (customerWantsCondiments()) { 21 | addCondiments() 22 | } 23 | } 24 | 25 | /** 26 | * 因为茶和咖啡的冲泡方式有差别 所以这里将冲泡的行为定义为抽象的,让子类去实现细节 27 | */ 28 | abstract fun brew() 29 | 30 | /** 31 | * 因为茶和咖啡添加不同的调味品 所以这里将冲泡的行为定义为抽象的,让子类去实现细节 32 | */ 33 | abstract fun addCondiments() 34 | 35 | /** 36 | * 因为茶和咖啡都有一样的烧水的行为,所以这里直接写在了基类里 37 | */ 38 | open fun boilWater() { 39 | println("Boiling water") 40 | } 41 | 42 | /** 43 | * 因为茶和咖啡都有一样的倒进杯子的行为,所以这里直接写在了基类里 44 | */ 45 | open fun pourInCup() { 46 | println("Pouring into cup") 47 | } 48 | 49 | /** 50 | * hook-钩子🪝 51 | * 该方法用来控制咖啡因饮料是否进行添加调味品,是一个空实现,子类可以覆写该方法控制算法的流程 52 | */ 53 | open fun customerWantsCondiments(): Boolean { 54 | return true 55 | } 56 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/observer/WeatherData.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.observer 2 | 3 | import java.util.ArrayList 4 | 5 | /** 6 | * 气象数据 被观察者 7 | */ 8 | class WeatherData : Subject { 9 | 10 | private var observers: ArrayList = ArrayList() 11 | 12 | private var temperature: Float = 0F 13 | 14 | private var humidity: Float = 0F 15 | 16 | private var pressure: Float = 0F 17 | 18 | /** 19 | * 当注册观察者时,将观察者添加到[observers]中 20 | */ 21 | override fun registerObserver(o: Observer) { 22 | observers.add(o) 23 | } 24 | 25 | /** 26 | * 当观察者取消注册时,将观察者从[observers]中移除 27 | */ 28 | override fun removeObserver(o: Observer) { 29 | observers.remove(o) 30 | } 31 | 32 | /** 33 | * 通知观察者 更新数据 34 | */ 35 | override fun notifyObservers() { 36 | observers.forEach { 37 | it.update(temperature, humidity, pressure) 38 | } 39 | } 40 | 41 | /** 42 | * 当从气象站得到更新的数据时 就要通知观察者 43 | */ 44 | fun measurementsChanged() { 45 | notifyObservers() 46 | } 47 | 48 | /** 49 | * 可以使用该方法 测试气象数据 50 | */ 51 | fun setMeasurements(temp: Float, humidity: Float, pressure: Float) { 52 | this.temperature = temp 53 | this.humidity = humidity 54 | this.pressure = pressure 55 | measurementsChanged() 56 | } 57 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/facade/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.facade 2 | 3 | /** 4 | * 测试家庭影院观赏电影(用轻松的方式) 5 | */ 6 | fun main() { 7 | // 我们在测试中,直接建立这些组件,正常的情况下,某个外观会被指派给客户使用,而不需要由客户自定创建外观 8 | val amp = Amplifier() 9 | val cd = CdPlayer() 10 | val dvd = DvdPlayer() 11 | val popcornPopper = PopcornPopper() 12 | val projector = Projector() 13 | val screen = Screen() 14 | val lights = TheaterLights() 15 | val tuner = Tuner() 16 | 17 | val homeTheaterFacade = HomeTheaterFacade(amp, tuner, dvd, cd, projector, screen, lights, popcornPopper) 18 | homeTheaterFacade.watchMovie("功夫熊猫") 19 | homeTheaterFacade.endMovie() 20 | 21 | // 输出结果 22 | // Get ready to watch a movie 功夫熊猫... 23 | // PopcornPopper -> on 24 | // PopcornPopper -> pop 25 | // TheaterLights -> dim 26 | // Screen -> down 27 | // Projector -> on 28 | // Projector -> wideScreenMode 29 | // Amplifier -> on 30 | // Amplifier -> setDvd 31 | // Amplifier -> setSurroundSound 32 | // Amplifier -> setVolume 5 33 | // DvdPlayer -> on 34 | // DvdPlayer -> play 35 | // Shutting movie theater down... 36 | // PopcornPopper -> off 37 | // TheaterLights -> on 38 | // Screen -> up 39 | // Projector -> off 40 | // Amplifier -> off 41 | // DvdPlayer -> stop 42 | // DvdPlayer -> eject 43 | // DvdPlayer -> off 44 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/factory/method/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.factory.method 2 | 3 | /** 4 | * 工厂方法模式 比萨商店-测试 5 | */ 6 | fun main() { 7 | 8 | val nyPizzaStore = NYPizzaStore() 9 | val chicagoPizzaStore = ChicagoPizzaStore() 10 | 11 | val nyCheesePizza = nyPizzaStore.orderPizza("cheese") 12 | println(" Ethan ordered a ${nyCheesePizza?.name} \n") 13 | 14 | val chicagoPizza = chicagoPizzaStore.orderPizza("cheese") 15 | println(" Joel ordered a ${chicagoPizza?.name} ") 16 | 17 | // 输出结果 18 | // Preparing NY style Sauce and Cheese Pizza 19 | // Tossing dough... 20 | // Adding sauce... 21 | // Adding toppings: 22 | // Grated Reggiano Cheese 23 | // Bake for 25 minutes at 350 24 | // Cutting the pizza into diagonal slices 25 | // Place pizza in official PizzaStore box 26 | // Ethan ordered a NY style Sauce and Cheese Pizza 27 | // 28 | // Preparing Chicago Style Deep Dish Cheese Pizza 29 | // Tossing dough... 30 | // Adding sauce... 31 | // Adding toppings: 32 | // Shredded Mozzarella Cheese 33 | // Bake for 25 minutes at 350 34 | // Cutting the pizza into square slices 35 | // Place pizza in official PizzaStore box 36 | // Joel ordered a Chicago Style Deep Dish Cheese Pizza 37 | 38 | // 两个比萨都准备好了,佐料都加上了,烘烤都完成了,也切片装盒了。 39 | // 超类从来不管细节。通过实例化正确的比萨类,子类会自行照料这一切 40 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/composite/MenuComponent.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.composite 2 | 3 | /** 4 | * 组件 5 | * 菜单组件这个角色是为叶节点和组合节点提供一个共同的接口 6 | * 所有的组件都必须实现该接口;然而,叶节点和组合节点的角色不同,所以有些方法可能并不适合某种节点。面对这种情况,有时候最好是抛出运行时异常 7 | * 因为有些方法只对菜单项有意义,而有些方法只对菜单有意义,默认实现是抛出[UnsupportedOperationException]异常。 8 | * 这样,如果菜单项或菜单不支持某个操作,他们就不需要做任何事情,直接继承默认实现就可以了 9 | */ 10 | abstract class MenuComponent { 11 | 12 | /* 组合相关方法 */ 13 | 14 | open fun add(menuComponent: MenuComponent) { 15 | throw UnsupportedOperationException() 16 | } 17 | 18 | open fun remove(menuComponent: MenuComponent) { 19 | throw UnsupportedOperationException() 20 | } 21 | 22 | open fun getChild(i: Int): MenuComponent { 23 | throw UnsupportedOperationException() 24 | } 25 | 26 | 27 | /* 这些方法是"操作"方法,它们被菜单项使用 */ 28 | 29 | open fun getName(): String { 30 | throw UnsupportedOperationException() 31 | } 32 | 33 | open fun getDescription(): String { 34 | throw UnsupportedOperationException() 35 | } 36 | 37 | open fun getPrice(): Double { 38 | throw UnsupportedOperationException() 39 | } 40 | 41 | open fun isVegetarian(): Boolean { 42 | throw UnsupportedOperationException() 43 | } 44 | 45 | /* print是"操作"方法,这个方法被菜单项和菜单同时使用 */ 46 | 47 | open fun print() { 48 | throw UnsupportedOperationException() 49 | } 50 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/facade/HomeTheaterFacade.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.facade 2 | 3 | /** 4 | * 家庭影院外观 5 | * 6 | * @constructor 将所有的家庭影院设备或物品组合进外观类 7 | */ 8 | class HomeTheaterFacade constructor( 9 | private val amp: Amplifier, 10 | private val tuner: Tuner, 11 | private val dvd: DvdPlayer, 12 | private val cd: CdPlayer, 13 | private val projector: Projector, 14 | private val screen: Screen, 15 | private val lights: TheaterLights, 16 | private val popper: PopcornPopper 17 | ) { 18 | 19 | /** 20 | * 将子系统的组件整合成一个统一的接口 21 | * watchMovie将我们之前手动进行的每项任务依次处理。请注意,每项任务都是委托子系统中相应的组件处理的 22 | * @param movie String 23 | */ 24 | fun watchMovie(movie: String) { 25 | println("Get ready to watch a movie $movie...") 26 | popper.on() 27 | popper.pop() 28 | lights.dim() 29 | screen.down() 30 | projector.on() 31 | projector.wideScreenMode() 32 | amp.on() 33 | amp.setDvd() 34 | amp.setSurroundSound() 35 | amp.setVolume(5) 36 | dvd.on() 37 | dvd.play() 38 | } 39 | 40 | /** 41 | * endMovie负责关闭一切,每项任务也都是委托子系统中合适的组件处理的 42 | */ 43 | fun endMovie() { 44 | println("Shutting movie theater down...") 45 | popper.off() 46 | lights.on() 47 | screen.up() 48 | projector.off() 49 | amp.off() 50 | dvd.stop() 51 | dvd.eject() 52 | dvd.off() 53 | } 54 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/singleton/java/SingletonDoubleLock.java: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.singleton.java; 2 | 3 | /** 4 | * 3.单例模式-懒汉式-双重校验锁 5 | * 加锁的懒汉模式看起来即解决了线程并发问题,又实现了延迟加载,然而它存在着性能问题,依然不够完美。 6 | * synchronized修饰的同步方法比一般方法要慢很多,如果多次调用getInstance(),累积的性能损耗就比较大了。 7 | * 因此就有了双重校验锁 8 | * 可以看到下面在同步代码块外多了一层instance为空的判断。由于单例对象只需要创建一次,如果后面再次调用getInstance()只需要直接返回单例对象。 9 | * 因此,大部分情况下,调用getInstance()都不会执行到同步代码块,从而提高了程序性能。 10 | * 不过还需要考虑一种情况,假如两个线程A、B,A执行了if (instance == null)语句,它会认为单例对象没有创建, 11 | * 此时线程切到B也执行了同样的语句,B也认为单例对象没有创建,然后两个线程依次执行同步代码块,并分别创建了一个单例对象。 12 | * 为了解决这个问题,还需要在同步代码块中增加if (instance == null)语句,也就是下面的代码2 13 | *

14 | * Java中的指令重排优化。所谓指令重排优化是指在不改变原语义的情况下,通过调整指令的执行顺序让程序运行的更快。 15 | * JVM中并没有规定编译器优化相关的内容,也就是说JVM可以自由的进行指令重排序的优化。 16 | * 由于指令重排优化的存在,导致初始化Singleton和将对象地址赋给instance字段的顺序是不确定的。 17 | * 在某个线程创建单例对象时,在构造方法被调用之前,就为该对象分配了内存空间并将对象的字段设置为默认值。 18 | * 此时就可以将分配的内存地址赋值给instance字段了,然而该对象可能还没有初始化。 19 | * 若紧接着另外一个线程来调用getInstance,取到的就是状态不正确的对象,程序就会出错 20 | * 在JDK1.5及之后版本增加了volatile关键字。 21 | * volatile的一个语义是禁止指令重排序优化,也就保证了instance变量被赋值的时候对象已经是初始化过的,从而避免了上面说到的问题 22 | */ 23 | public class SingletonDoubleLock { 24 | 25 | private static volatile SingletonDoubleLock instance = null; 26 | 27 | private SingletonDoubleLock() { 28 | } 29 | 30 | public static SingletonDoubleLock getInstance() { 31 | if (instance == null) { 32 | synchronized (SingletonDoubleLock.class) { 33 | if (instance == null) { //2 34 | instance = new SingletonDoubleLock(); 35 | } 36 | } 37 | } 38 | return instance; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 面向对象 - 设计模式 2 | 3 | 该存储库内包含了面向对象的23种经典设计模式的解读及示例代码,以Kotlin语言作为示例语言,其中这些案例出自《**Head First 设计模式**》、**Java源码**、**个人积累** 4 | 5 | ## 创建型设计模式 6 | 7 | - [x] 工厂方法模式(Factory Method Pattern) 8 | * 比萨店 - 《Head First 设计模式》 9 | - [x] 抽象工厂模式(Abstract Factory Pattern) 10 | * 针对于比萨店的原料工厂 - 《Head First 设计模式》 11 | - [x] 单例模式(Singleton Pattern) 12 | * Java 饿汉式单例 13 | * Java 线程安全懒汉式单例 14 | * Java 双重校验锁式单例 15 | * Java 静态内部类式单例 16 | * Java 枚举式单例 17 | * Kotlin 饿汉式单例 18 | * Kotlin 线程安全懒汉式单例 19 | * Kotlin 双重校验锁式单例 20 | * Kotlin 静态内部类式单例 21 | * Kotlin 枚举式单例 22 | - [x] 建造者模式(Builder Pattern) 23 | * 经典的Builder模式 - 《Android高级进阶》 24 | * 变种的Builder模式(Java) 25 | - [ ] 原型模式(Prototype Pattern) 26 | 27 | ## 行为型设计模式 28 | 29 | - [ ] 责任链模式(Chain of Responsibility Pattern) 30 | - [x] 命令模式(Command Pattern) 31 | * 家电自动化遥控器 - 《Head First 设计模式》 32 | - [ ] 解释器模式(Interpreter Pattern) 33 | - [x] 迭代器模式(Iterator Pattern) 34 | * 对象村餐厅和对象村煎饼屋合并新招的女招待 - 《Head First 设计模式》 35 | - [ ] 中介者模式(Mediator Pattern) 36 | - [ ] 备忘录模式(Memento Pattern) 37 | - [x] 观察者模式(Observer Pattern) 38 | * 气象站应用 - 《Head First 设计模式》 39 | - [x] 策略模式(Strategy Pattern) 40 | * 模拟鸭子应用 - 《Head First 设计模式》 41 | - [x] 模板方法模式(Template Pattern) 42 | * 星巴兹咖啡师傅训练手册 - 《Head First 设计模式》 43 | - [ ] 访问者模式(Visitor Pattern) 44 | - [x] 状态模式(State Pattern) 45 | * 糖果机 - 《Head First 设计模式》 46 | 47 | ## 结构型设计模式 48 | 49 | - [x] 组合模式(Composite Pattern) 50 | * 对象村餐厅和对象村煎饼屋合并后又在餐厅菜单中添加了饭后甜点菜单 - 《Head First 设计模式》 51 | - [ ] 享元模式(Flyweight Pattern) 52 | - [ ] 代理模式(Proxy Pattern) 53 | - [ ] 桥接模式(Bridge Pattern) 54 | - [x] 装饰器模式(Decorator Pattern) 55 | * 星巴兹咖啡应用 - 《Head First 设计模式》 56 | * Java I/O - JDK 57 | - [x] 适配器模式(Adapter Pattern) 58 | * 伪装成鸭子的火鸡 - 《Head First 设计模式》 59 | * 兼容Java早期集合枚举器的集合迭代器 - 《Head First 设计模式》 60 | - [x] 外观模式(Facade Pattern) 61 | * 家庭影院 - 《Head First 设计模式》 -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/state/GumballMachine.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.state 2 | 3 | /** 4 | * 糖果机 5 | * @property count Int 糖果的数量 6 | */ 7 | class GumballMachine(var count: Int) { 8 | 9 | /** 10 | * 售罄状态 11 | */ 12 | val mSoldOutState: State by lazy { SoldOutState(this) } 13 | 14 | /** 15 | * 没有25美分状态 16 | */ 17 | val mNoQuarterState: State by lazy { NoQuarterState(this) } 18 | 19 | /** 20 | * 有25美分状态 21 | */ 22 | val mHasQuarterState: State by lazy { HasQuarterState(this) } 23 | 24 | /** 25 | * 售出状态 26 | */ 27 | val mSoldState: State by lazy { SoldState(this) } 28 | 29 | /** 30 | * 赢家状态 31 | */ 32 | val mWinnerState: State by lazy { WinnerState(this) } 33 | 34 | /** 35 | * 初始状态为售罄 36 | */ 37 | private var mState: State = mSoldOutState 38 | 39 | init { 40 | // 如果初始值大于0 就将状态改为 NoQuarterState 41 | if (count > 0) { 42 | mState = mNoQuarterState 43 | } 44 | } 45 | 46 | fun insertQuarter() { 47 | mState.insertQuarter() 48 | } 49 | 50 | 51 | fun ejectQuarter() { 52 | mState.ejectQuarter() 53 | } 54 | 55 | fun turnCrank() { 56 | mState.turnCrank() 57 | mState.dispense() 58 | } 59 | 60 | // 请注意 我们不需要在GumballMachine内准备一个dispense()方法,因为这只是一个内部动作,用户不可以直接要求机器发放糖果 61 | // 但我们是在turnCrank()方法中调用dispense()方法的 62 | // fun dispense() {} 63 | 64 | /** 65 | * 这个方法允许其他的对象(像我们的状态对象)将机器的状态转换到不同的状态 66 | * @param state State 67 | */ 68 | fun setState(state: State) { 69 | mState = state 70 | } 71 | 72 | /** 73 | * 这个糖果机提供了一个releaseBall()辅助方法来释放糖果,并将count实例变量的值减一 74 | */ 75 | fun releaseBall() { 76 | println("A gumball comes rolling out the slot...") 77 | if (count != 0) { 78 | count -= 1 79 | } 80 | } 81 | 82 | // 这里是像toString()和refill()的其他方法 83 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/builder/variant1/User.java: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.builder.variant1; 2 | 3 | public class User { 4 | 5 | private final String mFirstName;// 名字 必选 6 | 7 | private final String mLastName; // 姓氏 必选 8 | 9 | private final String mGender; // 性别 可选 10 | 11 | private final int mAge; // 年龄 可选 12 | 13 | private final String mPhoneNo; // 电话 可选 14 | 15 | private User(Builder builder) { 16 | this.mFirstName = builder.firstName; 17 | this.mLastName = builder.lastName; 18 | this.mGender = builder.gender; 19 | this.mAge = builder.age; 20 | this.mPhoneNo = builder.phoneNo; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return "User{" + 26 | "mFirstName='" + mFirstName + '\'' + 27 | ", mLastName='" + mLastName + '\'' + 28 | ", mGender='" + mGender + '\'' + 29 | ", mAge=" + mAge + 30 | ", mPhoneNo='" + mPhoneNo + '\'' + 31 | '}'; 32 | } 33 | 34 | public static class Builder { 35 | 36 | private final String firstName;// 名字 必选 37 | 38 | private final String lastName; // 姓氏 必选 39 | 40 | private String gender; // 性别 可选 41 | 42 | private int age; // 年龄 可选 43 | 44 | private String phoneNo; // 电话 可选 45 | 46 | 47 | public Builder(String firstName, String lastName) { 48 | this.firstName = firstName; 49 | this.lastName = lastName; 50 | } 51 | 52 | public Builder gender(String gender) { 53 | this.gender = gender; 54 | return this; 55 | } 56 | 57 | public Builder age(int age) { 58 | this.age = age; 59 | return this; 60 | } 61 | 62 | public Builder phoneNo(String phoneNo) { 63 | this.phoneNo = phoneNo; 64 | return this; 65 | } 66 | 67 | public User builder() { 68 | return new User(this); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/iterator/PancakeHouseMenu.java: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.iterator; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | 6 | /** 7 | * 煎饼屋菜单 8 | * 煎饼屋的菜单使用的是ArrayList进行维护 9 | */ 10 | public class PancakeHouseMenu implements Menu { 11 | 12 | private final ArrayList menuItems; 13 | 14 | public PancakeHouseMenu() { 15 | // 煎饼屋使用一个ArrayList存储他的菜单项 16 | menuItems = new ArrayList<>(); 17 | 18 | // 在菜单的构造器中,每一个菜单项都会被加入到ArrayList中 19 | // 每一个菜单项都有一个名称、一个叙述、是否为素食,还有价格 20 | addItem("K&B's Pancake Breakfast", 21 | "Pancakes with scrambled eggs and toast", 22 | true, 23 | 2.99); 24 | 25 | addItem("Regular Pancake Breakfast", 26 | "Pancakes with fried eggs, sausage", 27 | false, 28 | 2.99); 29 | 30 | addItem("Blueberry Pancakes", 31 | "Pancakes made with fresh blueberries and blueberry syrup", 32 | true, 33 | 3.49); 34 | 35 | addItem("Waffles", 36 | "Waffles with your choice of blueberries or strawberries", 37 | true, 38 | 3.59); 39 | } 40 | 41 | /** 42 | * 添加菜单项 43 | * 44 | * @param name String 名称 45 | * @param description String 描述 46 | * @param vegetarian boolean 是否为素食 47 | * @param price double 单价 48 | */ 49 | public void addItem(String name, String description, 50 | boolean vegetarian, double price) { 51 | MenuItem menuItem = new MenuItem(name, description, vegetarian, price); 52 | menuItems.add(menuItem); 53 | } 54 | 55 | /** 56 | * 返回菜单列表 57 | */ 58 | public ArrayList getMenuItems() { 59 | return menuItems; 60 | } 61 | 62 | /** 63 | * 创建迭代器,由于ArrayList拥有自己的迭代器 所以直接返回ArrayList的迭代器 64 | * 65 | * @return 66 | */ 67 | public Iterator createIterator() { 68 | return menuItems.iterator(); 69 | } 70 | 71 | // other menu methods here 72 | // 其他的菜单代码都依赖于ArrayList,所以他不希望重写全部的答案 73 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/RemoteControl.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | /** 4 | * 遥控器 拥有7个插槽的遥控器 5 | * 插槽的初始化使用了空对象模式 6 | */ 7 | class RemoteControl { 8 | 9 | private val onCommands = 10 | mutableListOf( 11 | NoCommand(), 12 | NoCommand(), 13 | NoCommand(), 14 | NoCommand(), 15 | NoCommand(), 16 | NoCommand(), 17 | NoCommand() 18 | ) 19 | 20 | private val offCommands = 21 | mutableListOf( 22 | NoCommand(), 23 | NoCommand(), 24 | NoCommand(), 25 | NoCommand(), 26 | NoCommand(), 27 | NoCommand(), 28 | NoCommand() 29 | ) 30 | 31 | /** 32 | * 引用每一次的命令 用于撤销 33 | */ 34 | private var undoCommand: Command = NoCommand() 35 | 36 | /** 37 | * 设置插槽的命令 38 | * @param slot Int 插槽位置 39 | * @param onCommand Command 开命令 40 | * @param offCommand Command 关命令 41 | */ 42 | fun setCommand(slot: Int, onCommand: Command, offCommand: Command) { 43 | onCommands[slot] = onCommand 44 | offCommands[slot] = offCommand 45 | } 46 | 47 | /** 48 | * 按下开按钮 49 | * @param slot Int 插槽位置 50 | */ 51 | fun onButtonWasPushed(slot: Int) { 52 | onCommands[slot].execute() 53 | undoCommand = onCommands[slot] 54 | } 55 | 56 | /** 57 | * 按下关按钮 58 | * @param slot Int 插槽位置 59 | */ 60 | fun offButtonWasPushed(slot: Int) { 61 | offCommands[slot].execute() 62 | undoCommand = offCommands[slot] 63 | } 64 | 65 | /** 66 | * 按下撤销按钮 67 | */ 68 | fun undoButtonWasPushed() { 69 | undoCommand.undo() 70 | } 71 | 72 | override fun toString(): String { 73 | val sb = StringBuffer() 74 | sb.append("\n------ Remote Control ------\n") 75 | (0 until onCommands.size).forEach { 76 | sb.append("[slot:$it on:${onCommands[it].javaClass.simpleName} off:${offCommands[it].javaClass.simpleName}]\n") 77 | } 78 | sb.append("\n----------- End -----------\n") 79 | return sb.toString() 80 | } 81 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/iterator/DinerMenu.java: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.iterator; 2 | 3 | import java.util.Arrays; 4 | import java.util.Iterator; 5 | 6 | /** 7 | * 餐厅菜单 8 | * 餐厅的菜单采用的是数组进行维护 9 | */ 10 | public class DinerMenu implements Menu { 11 | 12 | static final int MAX_ITEMS = 6; 13 | 14 | private int numberOfItems = 0; 15 | 16 | /** 17 | * 餐厅菜单使用的是数组,所以可以控制菜单的长度 18 | */ 19 | private final MenuItem[] menuItems; 20 | 21 | public DinerMenu() { 22 | menuItems = new MenuItem[MAX_ITEMS]; 23 | 24 | addItem("Vegetarian BLT", 25 | "(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99); 26 | addItem("BLT", 27 | "Bacon with lettuce & tomato on whole wheat", false, 2.99); 28 | addItem("Soup of the day", 29 | "Soup of the day, with a side of potato salad", false, 3.29); 30 | addItem("Hotdog", 31 | "A hot dog, with sauerkraut, relish, onions, topped with cheese", 32 | false, 3.05); 33 | addItem("Steamed Veggies and Brown Rice", 34 | "Steamed vegetables over brown rice", true, 3.99); 35 | addItem("Pasta", 36 | "Spaghetti with Marinara Sauce, and a slice of sourdough bread", 37 | true, 3.89); 38 | } 39 | 40 | /** 41 | * 添加元素 创建一个MenuItem添加进数组内 并且会检查数组是否超出了它的长度控制 42 | * 43 | * @param name String 名称 44 | * @param description String 描述 45 | * @param vegetarian boolean 是否为素食 46 | * @param price double 单价 47 | */ 48 | public void addItem(String name, String description, 49 | boolean vegetarian, double price) { 50 | MenuItem menuItem = new MenuItem(name, description, vegetarian, price); 51 | if (numberOfItems >= MAX_ITEMS) { 52 | System.err.println("Sorry, menu is full! Can't add item to menu"); 53 | } else { 54 | menuItems[numberOfItems] = menuItem; 55 | numberOfItems = numberOfItems + 1; 56 | } 57 | } 58 | 59 | /** 60 | * 返回数组 61 | */ 62 | public MenuItem[] getMenuItems() { 63 | return menuItems; 64 | } 65 | 66 | /** 67 | * 这里使用Java 8 的Stream操作数组,返回一个迭代器 68 | */ 69 | public Iterator createIterator() { 70 | return Arrays.stream(menuItems).iterator(); 71 | } 72 | 73 | // other menu methods here 74 | // 同煎饼屋一样 这里还有很多其他的菜单代码依赖于这个菜单数组,所以厨师也不想重写那么多代码,不想更换数据结构 75 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/creational/singleton/kotlin/KtSingletonDoubleLock.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.creational.singleton.kotlin 2 | 3 | /** 4 | * 双重校验锁式 5 | * Lazy是接受一个 lambda 并返回一个 Lazy 实例的函数,返回的实例可以作为实现延迟属性的委托 6 | * 第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果,后续调用 get() 只是返回记录的结果 7 | * Lazy默认的线程模式就是 LazyThreadSafetyMode.SYNCHRONIZED 内部默认双重校验锁 8 | * # Lazy内部实现 9 | * ``` 10 | * public fun lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy = 11 | * when (mode) { 12 | * LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer) 13 | * LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer) 14 | * LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer) 15 | * } 16 | * ``` 17 | * ### Lazy接口 18 | * ``` 19 | * public interface Lazy { 20 | * //当前实例化对象,一旦实例化后,该对象不会再改变 21 | * public val value: T 22 | * //返回true表示,已经延迟实例化过了,false 表示,没有被实例化, 23 | * //一旦方法返回true,该方法会一直返回true,且不会再继续实例化 24 | * public fun isInitialized(): Boolean 25 | * } 26 | * ``` 27 | * ### SynchronizedLazyImpl 28 | * ``` 29 | * private class SynchronizedLazyImpl(initializer: () -> T, lock: Any? = null) : Lazy, Serializable { 30 | * private var initializer: (() -> T)? = initializer 31 | * @Volatile private var _value: Any? = UNINITIALIZED_VALUE 32 | * // final field is required to enable safe publication of constructed instance 33 | * private val lock = lock ?: this 34 | * 35 | * override val value: T 36 | * get() { 37 | * val _v1 = _value 38 | * //判断是否已经初始化过,如果初始化过直接返回,不在调用高级函数内部逻辑 39 | * if (_v1 !== UNINITIALIZED_VALUE) { 40 | * @Suppress("UNCHECKED_CAST") 41 | * return _v1 as T 42 | * } 43 | * 44 | * return synchronized(lock) { 45 | * val _v2 = _value 46 | * if (_v2 !== UNINITIALIZED_VALUE) { 47 | * @Suppress("UNCHECKED_CAST") (_v2 as T) 48 | * } 49 | * else { 50 | * //调用高级函数获取其返回值 51 | * val typedValue = initializer!!() 52 | * //将返回值赋值给_value,用于下次判断时,直接返回高级函数的返回值 53 | * _value = typedValue 54 | * initializer = null 55 | * typedValue 56 | * } 57 | * } 58 | * } 59 | * //省略部分代码 60 | * } 61 | * ``` 62 | */ 63 | class KtSingletonDoubleLock private constructor() { 64 | 65 | companion object { 66 | val instance by lazy { KtSingletonDoubleLock() } 67 | } 68 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/behavioral/command/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.behavioral.command 2 | 3 | fun main() { 4 | // testSimpleRemoteControl() 5 | // testRemoteControl() 6 | // testRemoteControlUndo() 7 | testMacroCommand() 8 | } 9 | 10 | /** 11 | * 测试简单遥控器 12 | */ 13 | fun testSimpleRemoteControl() { 14 | // 遥控器就是调用者,会传入一个命令对象,可以用来发出请求 15 | val control = SimpleRemoteControl() 16 | // 创建一个电灯💡对象,此对象也是请求的接收者 17 | val light = Light() 18 | // 创建一个命令,将接收者传给它 19 | val lightOnCommand = LightOnCommand(light) 20 | 21 | // 设置插槽的命令 22 | control.setCommand(lightOnCommand) 23 | // 按下按钮 24 | control.buttonWasPressed() 25 | // 输出结果 26 | // on 27 | } 28 | 29 | /** 30 | * 测试有七个插槽的遥控器 31 | */ 32 | fun testRemoteControl() { 33 | val light = Light() 34 | val stereo = Stereo() 35 | 36 | val lightOnCommand = LightOnCommand(light) 37 | val lightOffCommand = LightOffCommand(light) 38 | 39 | val stereoOnWithCDCommand = StereoOnWithCDCommand(stereo) 40 | val stereoOffCommand = StereoOffCommand(stereo) 41 | 42 | val remoteControl = RemoteControl() 43 | remoteControl.setCommand(0, lightOnCommand, lightOffCommand) 44 | remoteControl.setCommand(1, stereoOnWithCDCommand, stereoOffCommand) 45 | 46 | println(remoteControl.toString()) 47 | 48 | remoteControl.onButtonWasPushed(0) 49 | remoteControl.onButtonWasPushed(1) 50 | 51 | remoteControl.offButtonWasPushed(0) 52 | remoteControl.offButtonWasPushed(1) 53 | // 输出结果 54 | // ------ Remote Control ------ 55 | // [slot:0 on:LightOnCommand off:LightOffCommand] 56 | // [slot:1 on:StereoOnWithCDCommand off:StereoOffCommand] 57 | // [slot:2 on:NoCommand off:NoCommand] 58 | // [slot:3 on:NoCommand off:NoCommand] 59 | // [slot:4 on:NoCommand off:NoCommand] 60 | // [slot:5 on:NoCommand off:NoCommand] 61 | // [slot:6 on:NoCommand off:NoCommand] 62 | // 63 | // ----------- End ----------- 64 | // 65 | // Light -> on 66 | // Stereo -> on 67 | // Stereo -> set CD 68 | // Stereo -> set volume 11 69 | // Light -> off 70 | // Stereo -> off 71 | } 72 | 73 | /** 74 | * 测试有七个插槽的遥控器的撤销功能 75 | */ 76 | fun testRemoteControlUndo() { 77 | val remoteControl = RemoteControl() 78 | val ceilingFan = CeilingFan("Living Room") 79 | 80 | // 创建吊扇的四个档位命令 81 | val offCommand = CeilingFanOffCommand(ceilingFan) 82 | val lowCommand = CeilingFanLowCommand(ceilingFan) 83 | val mediumCommand = CeilingFanMediumCommand(ceilingFan) 84 | val highCommand = CeilingFanHighCommand(ceilingFan) 85 | 86 | remoteControl.setCommand(0, lowCommand, offCommand) 87 | remoteControl.setCommand(1, mediumCommand, offCommand) 88 | remoteControl.setCommand(2, highCommand, offCommand) 89 | 90 | println(remoteControl.toString()) 91 | 92 | remoteControl.onButtonWasPushed(0) 93 | remoteControl.offButtonWasPushed(0) 94 | remoteControl.undoButtonWasPushed() 95 | 96 | remoteControl.onButtonWasPushed(2) 97 | remoteControl.offButtonWasPushed(2) 98 | remoteControl.undoButtonWasPushed() 99 | 100 | // 输出结果 101 | // ------ Remote Control ------ 102 | // [slot:0 on:CeilingFanLowCommand off:CeilingOffCommand] 103 | // [slot:1 on:CeilingFanMediumCommand off:CeilingOffCommand] 104 | // [slot:2 on:CeilingFanHighCommand off:CeilingOffCommand] 105 | // [slot:3 on:NoCommand off:NoCommand] 106 | // [slot:4 on:NoCommand off:NoCommand] 107 | // [slot:5 on:NoCommand off:NoCommand] 108 | // [slot:6 on:NoCommand off:NoCommand] 109 | // 110 | // ----------- End ----------- 111 | // 112 | // CeilingFan - LOW 113 | // CeilingFan - OFF 114 | // CeilingFan - LOW 115 | // CeilingFan - HIGH 116 | // CeilingFan - OFF 117 | // CeilingFan - HIGH 118 | } 119 | 120 | /** 121 | * 测试宏命令 122 | */ 123 | fun testMacroCommand() { 124 | val remoteControl = RemoteControl() 125 | 126 | val light = Light() 127 | val stereo = Stereo() 128 | val ceilingFan = CeilingFan("") 129 | 130 | // 一组打开的命令 131 | val onCommands = mutableListOf() 132 | onCommands.add(LightOnCommand(light)) 133 | onCommands.add(StereoOnWithCDCommand(stereo)) 134 | onCommands.add(CeilingFanHighCommand(ceilingFan)) 135 | 136 | // 一组关闭的命令 137 | val offCommands = mutableListOf() 138 | offCommands.add(LightOffCommand(light)) 139 | offCommands.add(StereoOffCommand(stereo)) 140 | offCommands.add(CeilingFanOffCommand(ceilingFan)) 141 | 142 | val onMacroCommand = MacroCommand(onCommands) 143 | val offMacroCommand = MacroCommand(offCommands) 144 | 145 | remoteControl.setCommand(0, onMacroCommand, offMacroCommand) 146 | 147 | remoteControl.onButtonWasPushed(0) 148 | remoteControl.offButtonWasPushed(0) 149 | // 输出结果 150 | // Light -> on 151 | // Stereo -> on 152 | // Stereo -> set CD 153 | // Stereo -> set volume 11 154 | // CeilingFan - HIGH 155 | // Light -> off 156 | // Stereo -> off 157 | // CeilingFan - OFF 158 | } -------------------------------------------------------------------------------- /src/com/quyunshuo/designpattern/structural/composite/Main.kt: -------------------------------------------------------------------------------- 1 | package com.quyunshuo.designpattern.structural.composite 2 | 3 | /** 4 | * 测试组合模式 5 | */ 6 | fun main() { 7 | 8 | // 二级菜单 9 | val pancakeHouseMenu: MenuComponent = Menu("PANCAKE HOUSE MENU", "Breakfast") 10 | val dinerMenu: MenuComponent = Menu("DINER MENU", "Lunch") 11 | val cafeMenu: MenuComponent = Menu("CAFE MENU", "Dinner") 12 | 13 | // 顶层菜单 14 | val allMenus: MenuComponent = Menu("ALL MENUS", "All menus combined") 15 | allMenus.add(pancakeHouseMenu) 16 | allMenus.add(dinerMenu) 17 | allMenus.add(cafeMenu) 18 | 19 | // 二级菜单的菜单项 20 | pancakeHouseMenu.add( 21 | MenuItem("K&B's Pancake Breakfast", "Pancakes with scrambled eggs and toast", true, 2.99) 22 | ) 23 | pancakeHouseMenu.add( 24 | MenuItem("Regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false, 2.99) 25 | ) 26 | pancakeHouseMenu.add( 27 | MenuItem("Blueberry Pancakes", "Pancakes made with fresh blueberries and blueberry syrup", true, 3.49) 28 | ) 29 | pancakeHouseMenu.add( 30 | MenuItem("Waffles", "Waffles with your choice of blueberries or strawberries", true, 3.59) 31 | ) 32 | 33 | dinerMenu.add( 34 | MenuItem("Vegetarian BLT", "(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99) 35 | ) 36 | dinerMenu.add( 37 | MenuItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99) 38 | ) 39 | dinerMenu.add( 40 | MenuItem("Soup of the day", "A bowl of the soup of the day, with a side of potato salad", false, 3.29) 41 | ) 42 | dinerMenu.add( 43 | MenuItem("Hot Dog", "A hot dog, with saurkraut, relish, onions, topped with cheese", false, 3.05) 44 | ) 45 | dinerMenu.add( 46 | MenuItem("Steamed Veggies and Brown Rice", "A medly of steamed vegetables over brown rice", true, 3.99) 47 | ) 48 | 49 | dinerMenu.add( 50 | MenuItem("Pasta", "Spaghetti with marinara sauce, and a slice of sourdough bread", true, 3.89) 51 | ) 52 | 53 | // 三级菜单 54 | val dessertMenu: MenuComponent = Menu("DESSERT MENU", "Dessert of course!") 55 | dinerMenu.add(dessertMenu) 56 | dessertMenu.add( 57 | MenuItem("Apple Pie", "Apple pie with a flakey crust, topped with vanilla icecream", true, 1.59) 58 | ) 59 | dessertMenu.add( 60 | MenuItem("Cheesecake", "Creamy New York cheesecake, with a chocolate graham crust", true, 1.99) 61 | ) 62 | dessertMenu.add( 63 | MenuItem("Sorbet", "A scoop of raspberry and a scoop of lime", true, 1.89) 64 | ) 65 | 66 | cafeMenu.add( 67 | MenuItem( 68 | "Veggie Burger and Air Fries", 69 | "Veggie burger on a whole wheat bun, lettuce, tomato, and fries", 70 | true, 71 | 3.99 72 | ) 73 | ) 74 | cafeMenu.add( 75 | MenuItem("Soup of the day", "A cup of the soup of the day, with a side salad", false, 3.69) 76 | ) 77 | cafeMenu.add( 78 | MenuItem("Burrito", "A large burrito, with whole pinto beans, salsa, guacamole", true, 4.29) 79 | ) 80 | 81 | // 女招待 82 | val waitress = Waitress(allMenus) 83 | waitress.printMenu() 84 | 85 | // 输出结果 86 | // ALL MENUS, All menus combined 87 | // ------------------------ 88 | // 89 | // PANCAKE HOUSE MENU, Breakfast 90 | // ------------------------ 91 | // K&B's Pancake Breakfast(v), 2.99 92 | // -- Pancakes with scrambled eggs and toast 93 | // Regular Pancake Breakfast, 2.99 94 | // -- Pancakes with fried eggs, sausage 95 | // Blueberry Pancakes(v), 3.49 96 | // -- Pancakes made with fresh blueberries and blueberry syrup 97 | // Waffles(v), 3.59 98 | // -- Waffles with your choice of blueberries or strawberries 99 | // 100 | // DINER MENU, Lunch 101 | // ------------------------ 102 | // Vegetarian BLT(v), 2.99 103 | // -- (Fakin') Bacon with lettuce & tomato on whole wheat 104 | // BLT, 2.99 105 | // -- Bacon with lettuce & tomato on whole wheat 106 | // Soup of the day, 3.29 107 | // -- A bowl of the soup of the day, with a side of potato salad 108 | // Hot Dog, 3.05 109 | // -- A hot dog, with saurkraut, relish, onions, topped with cheese 110 | // Steamed Veggies and Brown Rice(v), 3.99 111 | // -- A medly of steamed vegetables over brown rice 112 | // Pasta(v), 3.89 113 | // -- Spaghetti with marinara sauce, and a slice of sourdough bread 114 | // 115 | // DESSERT MENU, Dessert of course! 116 | // ------------------------ 117 | // Apple Pie(v), 1.59 118 | // -- Apple pie with a flakey crust, topped with vanilla icecream 119 | // Cheesecake(v), 1.99 120 | // -- Creamy New York cheesecake, with a chocolate graham crust 121 | // Sorbet(v), 1.89 122 | // -- A scoop of raspberry and a scoop of lime 123 | // 124 | // CAFE MENU, Dinner 125 | // ------------------------ 126 | // Veggie Burger and Air Fries(v), 3.99 127 | // -- Veggie burger on a whole wheat bun, lettuce, tomato, and fries 128 | // Soup of the day, 3.69 129 | // -- A cup of the soup of the day, with a side salad 130 | // Burrito(v), 4.29 131 | // -- A large burrito, with whole pinto beans, salsa, guacamole 132 | } --------------------------------------------------------------------------------