各个设计模式解析
创建型模式 单例模式 Singleton 饿汉单例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class EagerSingleton { private static EagerSingleton instance = new EagerSingleton(); private EagerSingleton () { } public static EagerSingleton getInstance () { return instance; } }
在第一次加载类到内存中时就会初始化,所以创建实例本身是线程安全的。
懒汉单例 懒汉式,线程不安全 1 2 3 4 5 6 7 8 9 10 public class Singleton { private static Singleton instance; private Singleton () {} public static Singleton getInstance () { if (instance == null ) { instance = new Singleton(); } return instance; } }
懒汉式,线程安全 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Singleton { private volatile static Singleton instance; private Singleton () {} public static Singleton getSingleton () { if (instance == null ) { synchronized (Singleton.class) { if (instance == null ) { instance = new Singleton(); } } } return instance; } }
volatile
增加的作用主要是为了防止指令重排
这段代码被其他线程抢占执行,synchronize里面正好有指针,但未开辟内存空间,就会出现问题
优点 提供了对唯一实例的受控访问。 因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它,并为设计及开发团队提供了共享的概念。 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能。 允许可变数目的实例。我们可以基于单例模式进行扩展,使用与单例控制相似的方法来获得指定个数的对象实例。
缺点 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。 单例类的职责过重,在一定程度上违背了”单一职责原则”。 因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出; 现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术 因此,如果实例化的对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致对象状态的丢失。
建造者模式 Builder 建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class Data { private String data; private Data (Builder builder) { data = builder.data; } public static final class Builder { private String data; public Builder () { } public Builder data (String val) { data = val; return this ; } public Data build () { return new Data(this ); } } }
优点 在建造者模式中, 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象 。 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合”开闭原则”。
缺点 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
工厂模式 产品Factory 简单工厂(静态工厂) 简单工厂模式又称静态工厂方法模式。 存在的目的很简单:定义一个用于创建对象的接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 abstract class BMW { public BMW () { } } public class BMW320 extends BMW { public BMW320 () { System.out.println("制造-->BMW320" ); } } public class BMW523 extends BMW { public BMW523 () { System.out.println("制造-->BMW523" ); } } public class Factory { public static BMW createBMW (int type) { switch (type) { case 320 : return new BMW320(); case 523 : return new BMW523(); default : break ; } return null ; } } public class Customer { public static void main (String[] args) { BMW bmw320 = Factory.createBMW(320 ); BMW bmw523 = Factory.createBMW(523 ); } }
优点 使用工厂类,不必管这些对象究竟如何创建及如何组织的,明确了各自的职责和权利。
缺点 违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;如果需要添加新的类,则就需要改变工厂类了。对系统的维护和扩展非常不利;
适用范围 简单工厂模式:工厂类负责创建的对象比较少,客户只知道传入了工厂类的参数,对于始何创建对象(逻辑)不关心。
工厂方法 Factory产品类型 由之前的简单工厂模式(静态工厂模式)改造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 interface FactoryBMW { BMW createBMW () ; } public class FactoryBMW320 implements FactoryBMW { @Override public BMW320 createBMW () { return new BMW320(); } } public class FactoryBMW523 implements FactoryBMW { @Override public BMW523 createBMW () { return new BMW523(); } } public class Customer { public static void main (String[] args) { FactoryBMW320 factoryBMW320 = new FactoryBMW320(); BMW320 bmw320 = factoryBMW320.createBMW(); FactoryBMW523 factoryBMW523 = new FactoryBMW523(); BMW523 bmw523 = factoryBMW523.createBMW(); } }
优点 工厂方法模式是为了克服简单工厂模式的缺点(主要是为了满足OCP)而设计出来的。 简单工厂模式的工厂类随着产品类的增加需要增加很多方法(或代码)而工厂方法模式每个具体工厂类只完成单一任务,代码简洁。工厂方法模式完全满足OCP,即它有非常良好的扩展性。
缺点 不易于维护,假如某个具体产品类需要进行一定的修改,很可能需要修改对应的工厂类。当同时需要修改多个产品类的时候,对工厂类的修改会变得相当麻烦
适用范围:当一个类不知道它所必须创建对象的类或一个类希望由子类来指定它所创建的对象时,当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候,可以使用工厂方法。
抽象工厂 AbstractFactory 抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。
如果以上实例牵扯很多附属的实例,例如车牵扯引擎与空调
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 public interface Engine { } public class EngineA extends Engine { public EngineA () { System.out.println("制造-->EngineA" ); } } public class EngineBextends Engine { public EngineB () { System.out.println("制造-->EngineB" ); } } public interface Aircondition { } public class AirconditionA extends Aircondition { public AirconditionA () { System.out.println("制造-->AirconditionA" ); } } public class AirconditionB extends Aircondition { public AirconditionB () { System.out.println("制造-->AirconditionB" ); } } public interface AbstractFactory { public Engine createEngine () ; public Aircondition createAircondition () ; } public class FactoryBMW320 implements AbstractFactory { @Override public Engine createEngine () { return new EngineA(); } @Override public Aircondition createAircondition () { return new AirconditionA(); } } public class FactoryBMW523 implements AbstractFactory { @Override public Engine createEngine () { return new EngineB(); } @Override public Aircondition createAircondition () { return new AirconditionB(); } } public class Customer { public static void main (String[] args) { FactoryBMW320 factoryBMW320 = new FactoryBMW320(); factoryBMW320.createEngine(); factoryBMW320.createAircondition(); FactoryBMW523 factoryBMW523 = new FactoryBMW523(); factoryBMW320.createEngine(); factoryBMW320.createAircondition(); } }
优点 抽象工厂模式主要在于应对”新系列”的需求变化。
分离了具体的类,抽象工厂模式帮助你控制一个应用创建的对象的类,因为一个工厂封装创建产品对象的责任和过程。 这使得改变一个应用的具体工厂变得很容易。 它只需改变具体的工厂即可使用不同的产品配置,这是因为一个抽象工厂创建了一个完整的产品系列,所以整个产品系列会立刻改变。它有利于产品的一致性。当一个系列的产品对象被设计成一起工作时,一个应用一次只能使用同一个系列中的对象,这一点很重要,而抽象工厂很容易实现这一点。抽象工厂模式有助于这样的团队的分工,降低了模块间的耦合性,提高了团队开发效率。
缺点 抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。
抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。它有多个抽象产品类,每个抽象产品类可以派生出多个具体产品类,一个抽象工厂类,可以派生出多个具体工厂类,每个具体工厂类可以创建多个具体产品类的实例。每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结果。
适用范围 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。这个系统有多于一个的产品族,而系统只消费其中某一产品族。同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
原型模式 Prototype
实现Cloneable接口。只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。
重写Object类中的clone方法。Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此,Prototype类需要将clone方法的作用域修改为public类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Prototype implements Cloneable { public Prototype clone () { Prototype prototype = null ; try { prototype = (Prototype)super .clone(); prototype.list = (ArrayList) this .list.clone(); }catch (CloneNotSupportedException e){ e.printStackTrace(); } return prototype; } } class ConcretePrototype extends Prototype { public void show () { System.out.println("原型模式实现类" ); } } public class Client { public static void main (String[] args) { ConcretePrototype cp = new ConcretePrototype(); for (int i=0 ; i< 10 ; i++){ ConcretePrototype clonecp = (ConcretePrototype)cp.clone(); clonecp.show(); } } }
深浅拷贝 Object类的clone方法只会拷贝对象中的基本的数据类型(8种基本数据类型byte,char,short,int,long,float,double,boolean)
对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。
结构型模式 适配器模式 Adapter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class Adaptee { public void specificRequest () { System.out.println("被适配类具有 特殊功能..." ); } } interface Target { public void request () ; } class ConcreteTarget implements Target { public void request () { System.out.println("普通类 具有 普通功能..." ); } } class Adapter extends Adaptee implements Target { public void request () { super .specificRequest(); } } public class Client { public static void main (String[] args) { Target concreteTarget = new ConcreteTarget(); concreteTarget.request(); Target adapter = new Adapter(); adapter.request(); } }
适用范围 SpringMVC RequestMappingHandlerAdapter
invocableMethod.invokeAndHandle运用了这种模式 与HandlerAdapter#handle结合使用了起来
装饰者模式 Decorator 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 public class DesignPatterns { public static void main (String[] args) { Human person = new Person(); Decorator decorator = new Decorator_two(new Decorator_first( new Decorator_zero(person))); decorator.wearClothes(); decorator.walkToWhere(); } } interface Human { public void wearClothes () ; public void walkToWhere () ; } abstract class Decorator implements Human { private Human human; public Decorator (Human human) { this .human = human; } public void wearClothes () { human.wearClothes(); } public void walkToWhere () { human.walkToWhere(); } } class Decorator_zero extends Decorator { public Decorator_zero (Human human) { super (human); } public void goHome () { System.out.println("进房子。。" ); } public void findMap () { System.out.println("书房找找Map。。" ); } @Override public void wearClothes () { super .wearClothes(); goHome(); } @Override public void walkToWhere () { super .walkToWhere(); findMap(); } } class Decorator_first extends Decorator { public Decorator_first (Human human) { super (human); } public void goClothespress () { System.out.println("去衣柜找找看。。" ); } public void findPlaceOnMap () { System.out.println("在Map上找找。。" ); } @Override public void wearClothes () { super .wearClothes(); goClothespress(); } @Override public void walkToWhere () { super .walkToWhere(); findPlaceOnMap(); } } class Decorator_two extends Decorator { public Decorator_two (Human human) { super (human); } public void findClothes () { System.out.println("找到一件D&G。。" ); } public void findTheTarget () { System.out.println("在Map上找到神秘花园和城堡。。" ); } @Override public void wearClothes () { super .wearClothes(); findClothes(); } @Override public void walkToWhere () { super .walkToWhere(); findTheTarget(); } } class Person implements Human { @Override public void wearClothes () { System.out.println("穿什么呢。。" ); } @Override public void walkToWhere () { System.out.println("去哪里呢。。" ); } }
适用范围 动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活。
设计初衷:通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性 同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。
现在需要一个汉堡,主体是鸡腿堡,可以选择添加生菜、酱、辣椒等等许多其他的配料,这种情况下就可以使用装饰者模式。
只要嵌套装饰者,装饰者的行为也会添加上去
优点 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合”开闭原则”
缺点 使用装饰模式进行系统设计时将产生很多小对象 这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。 这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
代理模式 Proxy 给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用
通过引入代理对象的方式来间接访问目标对象
代购(代理对象) 代替 我(真实对象) 去买Mac(间接访问的操作)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public interface Subject { public void buyMac () ; } public class RealSubject implement Subject { @Override public void buyMac () { System.out.println(”买一台Mac“); } } public class Proxy implements Subject { @Override public void buyMac{ RealSubject realSubject = new RealSubject(); realSubject.buyMac(); this .WrapMac(); } public void WrapMac () { System.out.println("用盒子包装好Mac" ); } } public class ProxyPattern { public static void main (String[] args) { Subject proxy = new Proxy(); proxy.buyMac(); } }
优点 防止直接访问目标对象给系统带来的不必要复杂性。 协调调用者和被调用者,降低了系统的耦合度 代理对象作为客户端和目标对象之间的中介,起到了保护目标对象的作用
缺点 由于在客户端和真实主题之间增加了代理对象,因此会造成请求的处理速度变慢; 实现代理模式需要额外的工作(有些代理模式的实现非常复杂),从而增加了系统实现的复杂度。
门面模式(外观模式) Facade 引进门面模式,设置一个接待员,又接待员提供各类服务 例如:医院可以设置一个接待员的位置,由接待员负责代为挂号、划价、缴费、取药等。 这个接待员就是门面模式的体现,病人只接触接待员,由接待员与各个部门打交道。
门面(Facade)角色:客户端可以调用这个角色的方法。 此角色知晓相关的(一个或者多个)子系统的功能和责任。在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去。
子系统(SubSystem)角色:可以同时有一个或者多个子系统。 每个子系统都不是一个单独的类,而是一个类的集合(如上面的子系统就是由ModuleA、ModuleB、ModuleC三个类组合而成)。每个子系统都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另外一个客户端而已。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class ModuleA { public void testA () { System.out.println("调用ModuleA中的testA方法" ); } } public class ModuleB { public void testB () { System.out.println("调用ModuleB中的testB方法" ); } } public class ModuleC { public void testC () { System.out.println("调用ModuleC中的testC方法" ); } } public class Facade { public void test () { ModuleA a = new ModuleA(); a.testA(); ModuleB b = new ModuleB(); b.testB(); ModuleC c = new ModuleC(); c.testC(); } } public class Client { public static void main (String[] args) { Facade facade = new Facade(); facade.test(); } }
优点
门面模式松散了客户端与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护。
门面模式让子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟门面类交互就可以了。
通过合理使用Facade,可以帮助我们更好地划分访问的层次。有些方法是对系统外的,有些方法是系统内部使用的。 把需要暴露给外部的功能集中到门面中,这样既方便客户端使用,也很好地隐藏了内部的细节。
缺点 不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了”开闭原则”。
享元模式(共享模式) Flyweight
一个系统中如果有多个相同的对象,那么只共享一份就可以了 比如说一个文本系统,每个字母定一个对象,那么大小写字母一共就是52个,那么就要定义52个对象。 如果有一个1M的文本,那么字母是何其的多,如果每个字母都定义一个对象那么内存早就爆了。 那么如果要是每个字母都共享一个对象,那么就大大节约了资源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 public abstract class Flyweight { public abstract void operation () ; } public class ConcreteFlyweight extends Flyweight { private String string; public ConcreteFlyweight (String str) { string = str; } public void operation () { System.out.println("Concrete---Flyweight : " + string); } } public class FlyweightFactory { private Hashtable flyweights = new Hashtable(); public FlyweightFactory () {} public Flyweight static getFlyWeight (Object obj) { Flyweight flyweight = (Flyweight) flyweights.get(obj); if (flyweight == null ){ flyweight = new ConcreteFlyweight((String)obj); flyweights.put(obj, flyweight); } return flyweight; } public int getFlyweightSize () { return flyweights.size(); } } public class FlyweightPattern { FlyweightFactory factory = new FlyweightFactory(); Flyweight fly1; Flyweight fly2; Flyweight fly3; Flyweight fly4; Flyweight fly5; Flyweight fly6; public FlyweightPattern () { fly1 = factory.getFlyWeight("Google" ); fly2 = factory.getFlyWeight("Qutr" ); fly3 = factory.getFlyWeight("Google" ); fly4 = factory.getFlyWeight("Google" ); fly5 = factory.getFlyWeight("Google" ); fly6 = factory.getFlyWeight("Google" ); } public void showFlyweight () { fly1.operation(); fly2.operation(); fly3.operation(); fly4.operation(); fly5.operation(); fly6.operation(); int objSize = factory.getFlyweightSize(); System.out.println("objSize = " + objSize); } public static void main (String[] args) { System.out.println("The FlyWeight Pattern!" ); FlyweightPattern fp = new FlyweightPattern(); fp.showFlyweight(); } }
定义了6个对象,其中有5个是相同的 按照Flyweight模式的定义”Google”应该共享一个对象 在实际的对象数中我们可以看出实际的对象却是只有2个。
优点 享元模式的优点在于它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
缺点 享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。
行为型模式 策略模式 Strategy
策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 public interface ICalculatorStrategy { public int operate (String exp) ; } public abstract class AbstractCalculatorStrategy { public int [] split(String exp,String opt){ String array[] = exp.split(opt); int arrayInt[] = new int [2 ]; arrayInt[0 ] = Integer.parseInt(array[0 ]); arrayInt[1 ] = Integer.parseInt(array[1 ]); return arrayInt; } } public class Plus extends AbstractCalculatorStrategy implements ICalculatorStrategy { @Override public int operate (String exp) { int arrayInt[] = split(exp,"\\+" ); return arrayInt[0 ]+arrayInt[1 ]; } } public class Minus extends AbstractCalculatorStrategy implements ICalculatorStrategy { @Override public int operate (String exp) { int arrayInt[] = split(exp,"-" ); return arrayInt[0 ]-arrayInt[1 ]; } } public class Context { private ICalculatorStrategy strategy; public Context (ICalculatorStrategy strategy) { this .strategy = strategy; } public void setStrategy (ICalculatorStrategy strategy) { this .strategy = strategy; } public void operate () { this .strategy.operate(); } } public class StrategyTest { public static void main (String[] args) { String exp = "2+8" ; int result = 0 ; Context context; context = new Context(new Plus()); result = context.operate(exp); context.setStrategy(new Minus()); result = context.operate(exp); } }
以上就是策略模式,多种不同解决方案(算法)动态切换,起到改变对象行为的效果。
优点
策略模式提供了对”开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
策略模式提供了管理相关的算法族的办法。
策略模式提供了可以替换继承关系的办法。
使用策略模式可以避免使用多重条件转移语句。
缺点
客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。
模板模式 Abstract 模式中的角色
抽象类(AbstractClass):实现了模板方法,定义了算法的骨架。
具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 public abstract class AbstractPerson { public void prepareGotoSchool () { dressUp(); eatBreakfast(); takeThings(); } protected abstract void dressUp () ; protected abstract void eatBreakfast () ; protected abstract void takeThings () ; } public class Student extends AbstractPerson { @Override protected void dressUp () { System.out.println("穿校服" ); } @Override protected void eatBreakfast () { System.out.println("吃妈妈做好的早饭" ); } @Override protected void takeThings () { System.out.println("背书包,带上家庭作业和红领巾" ); } } public class Teacher extends AbstractPerson { @Override protected void dressUp () { System.out.println("穿工作服" ); } @Override protected void eatBreakfast () { System.out.println("做早饭,照顾孩子吃早饭" ); } @Override protected void takeThings () { System.out.println("带上昨晚准备的考卷" ); } } public class Client { public static void main (String[] args) { Student student = new Student() student.prepareGotoSchool(); Teacher teacher = new Teacher() teacher.prepareGotoSchool(); } }
优点 模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。 子类实现算法的某些细节,有助于算法的扩展。 通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合”开放-封闭原则”。
缺点 每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。
观察者模式 Observer/Observable & Watcher/Watched 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 interface Observer { void update (Subject subject) ; } class ProgramMonkeyObserver implements Observer { @Override public void update (Subject subject) { String state = ((SDKDownloadSubject)subject).getState(); System.out.println("Programer look the SDK download process is: " +state); } } abstract class Subject { private List<Observer> list = new ArrayList<>(); public void attach (Observer observer) { list.add(observer); } public void detach (Observer observer) { list.remove(observer); } public void motifyObservers () { for (Observer obs : list) { obs.update(this ); } } } class SDKDownloadSubject extends Subject { private String mState; public String getState () { return mState; } public void netProcessChange (String data) { mState = data; this .motifyObservers(); } } public class Main { public static void main (String[] args) { SDKDownloadSubject sdkDownloadSubject = new SDKDownloadSubject(); Observer observer = new ProgramMonkeyObserver(); sdkDownloadSubject.attach(observer); sdkDownloadSubject.netProcessChange("1%" ); sdkDownloadSubject.netProcessChange("51%" ); sdkDownloadSubject.netProcessChange("100%" ); } }
优点
观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。
观察者模式在观察目标和观察者之间建立一个抽象的耦合。
观察者模式支持广播通信。
观察者模式符合”开闭原则”的要求。
缺点
如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
国内查看评论需要代理~