文章目录
一、什么是设计模式
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
使用设计模式是为了可重用代码、避免程序大量修改,同时使代码更容易被他人理解、并且保证代码可靠性。
模式:在某些场景下,针对某类问题的某种通用的解决方案。
场景:项目所在的环境
问题:约束条件,项目目标等
解决方案:通用、可复用的设计,解决约束达到目标。
1、设计模式的三个分类
创建型模式:对象实例化的模式,创建型模式用于解耦对象的实例化过程。
结构型模式:把类或对象结合在一起形成一个更大的结构。
行为型模式:类和对象如何交互,及划分责任和算法。
23种设计模式,其中,创建型有5种,结构型有7种,行为型有11种。
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
二、各分类模式的关键点
1、创建型模式
创建型模式5种。
单例模式:某个类只能有一个实例,提供一个全局的访问点。
工厂方法:定义一个创建对象的接口,让子类决定实例化那个类。
抽象工厂:创建相关或依赖对象的家族,而无需明确指定具体类。
建造者模式:封装一个复杂对象的构建过程,并可以按步骤构造。
原型模式:通过复制现有的实例来创建新的实例。
2、结构型模式
结构型模式7种。
适配器模式:将一个类的方法接口转换成客户希望的另外一个接口。
桥接模式:将抽象部分和它的实现部分分离,使它们都可以独立的变化。
组合模式:将对象组合成树形结构以表示“”部分-整体“”的层次结构。
装饰模式:动态的给对象添加新的功能。
亨元(蝇量)模式:通过共享技术来有效的支持大量细粒度的对象。
外观模式:对外提供一个统一的方法,来访问子系统中的一群接口。
代理模式:为其他对象提供一个代理以便控制这个对象的访问。
3、行为型模式
行为型模式11种。
访问者模式:在不改变数据结构的前提下,增加作用于一组对象元素的新功能。
模板模式:定义一个算法结构,而将一些步骤延迟到子类实现。
策略模式:定义一系列算法,把他们封装起来,并且使它们可以相互替换。
状态模式:允许一个对象在其对象内部状态改变时改变它的行为。
观察者模式:对象间的一对多的依赖关系。
备忘录模式:在不破坏封装的前提下,保持对象的内部状态。
中介者模式:用一个中介对象来封装一系列的对象交互。
迭代器模式:一种遍历访问聚合对象中各个元素的方法,不暴露该对象的内部结构。
解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器。
命令模式:将命令请求封装为一个对象,使得可以用不同的请求来进行参数化。
责任链模式:将请求的发送者和接收者解耦,使的多个对象都有处理这个请求的机会。
三、概说23种设计模式
1、单例模式
创建型设计模式。
简单说来,单例模式(也叫单件模式)的作用就是保证在整个应用程序的生命周期中,任
何一个时刻,单例类的实例都只存在一个(当然也可以不存在)。
单例模式确保某一个类只有一个实例,而且自行实例化,并向整个系统提供这个实例单例模式。单例模式只应在有真正的“单一实例”需求时才可使用。
全局变量和单例模式的区别为:首先,全局变量是对一个对象的静态引用,全局变量确实可以提供单例模式实现的全局访问这个功能,但是它并不能保证应用程序中只有一个实例;其次,编码规范也明确指出应该要少用全局变量,因为过多使用全局变量,会造成代码难读;最后全局变量并不能实现继承(虽然单例模式在继承上也不能很好地处理,但是还是可以实现继承的)。而单例模式在类中保存了它的唯一实例——这个类,它可以保证只能创建一个实例,同时它还提供了一个访问该唯一实例的全局访问点。
使用单例模式,需要注意的是,单例模式用来保证系统中一个类只有一个实例。单例类的构造函数必须为私有,同时单例类必须提供一个全局访问点。
单例模式的主要优点就是节约系统资源、提高了系统效率,同时也能够严格控制客户对它的访问。也许就是因为系统中只有一个实例,这样就导致了单例类的职责过重,违背了“单一职责原则”,同时也没有抽象类,所以扩展起来有一定的困难。
(1)饿汉模式
/**
*
* @author Vincent
* 线程安全 但是容易产生垃圾对象,没有加锁执行效率会比较高
* 但不是懒加载 类一加载的时候就进行初始化 浪费内存
*
*/
1. public class Singleton {
2. // 直接创建对象
3. public static Singleton instance = new Singleton();
4.
5. // 私有化构造函数
6. private Singleton() {
7. }
8.
9. // 返回对象实例
10. public static Singleton getInstance() {
11. return instance;
12. }
13. }
(2)懒汉式
1. public class Singleton {
2. // 声明变量
3. private static volatile Singleton singleton = null;
4.
5. // 私有构造函数
6. private Singleton() {
7. }
8.
9. // 提供对外方法
10. public static Singleton getInstance() {
11. if (singleton == null) {
12. synchronized (Singleton.class) {
13. if (singleton == null) {
14. singleton = new Singleton();
15. }
16. }
17. }
18. return singleton;
19. }
20. }
2、工厂设计模式
什么是工厂模式
一、
工厂 模式专门负责实例化有大量公共接口的类。工厂模式可以动态块决定将哪一个类实例化,而不必事先知道每次要实例化哪一个类。
客户类和工厂类是分开的。消费者无论什么时候需要某种产品,需要做的只是向工厂提出请求即可。消费者无须修改就可以接纳新产品。当然也存在缺点,就是当产品修改时,工厂”类也要做相应的修改。
二、
工厂模式分为工厂方法模式和抽象工厂模式。
工厂方法模式分为三种:
1)普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
2)多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
3)静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
三、
工厂方法模式的设计类图:
Product 为产品的接口或基类,所有产品都实现这个接口或抽象类( 例如ConcreteProduct),这样就可以在运行时根据需求创建对应的产品类。Creator实现了对产品的所有操作方法,而不实现产品对象的实例化。产品的实例化由Creator 的子类来完成。
(1)普通工厂模式
1. public interface Sender {
2. public void Send();
3. }
4. public class MailSender implements Sender {
5.
6. @Override
7. public void Send() {
8. System.out.println("this is mail sender!");
9. }
10.}
11. public class SmsSender implements Sender {
12.
13. @Override
14. public void Send() {
15. System.out.println("this is sms sender!");
16. }
17. }
18. public class SendFactory {
19. public Sender produce(String type) {
20. if ("mail".equals(type)) {
21. return new MailSender();
22. } else if ("sms".equals(type)) {
23. return new SmsSender();
24. } else {
25. System.out.println("请输入正确的类型!");
26. return null;
27. }
28. }
29. }
(2)多个工厂方法模式
该模式是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
1. public class SendFactory {
2. public Sender produceMail(){
3. return new MailSender();
4. }
5.
6. public Sender produceSms(){
7. return new SmsSender();
8. }
9. }
10.
11. public class FactoryTest {
12. public static void main(String[] args) {
13. SendFactory factory = new SendFactory();
14. Sender sender = factory.produceMail();
15. sender.send();
16. }
17. }
(3)静态工厂方法模式
将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
1. public class SendFactory {
2. public static Sender produceMail(){
3. return new MailSender();
4. }
5.
6. public static Sender produceSms(){
7. return new SmsSender();
8. }
9. }
10.
11.
12. public class FactoryTest {
13. public static void main(String[] args) {
14. Sender sender = SendFactory.produceMail();
15. sender.send();
16. }
17. }
(4)抽象工厂模式
一、
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则。
所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
二、
抽象工厂模式的设计类图:
AbstractProductA和AbstractProductB代表2个产品家族,实现这些接口的类代表具体的产品。AbstractFactory 为创建产品的接口,能够创建这个产品家族的中所有类型的产品,它的子类可以根据具体情况创建对应的产品。
1. public interface Provider {
2. public Sender produce();
3. }
4. -------------------------------------------------------------------------------------
5. public interface Sender {
6. public void send();
7. }
8. -------------------------------------------------------------------------------------
9. public class MailSender implements Sender {
10.
11. @Override
12. public void send() {
13. System.out.println("this is mail sender!");
14. }
15. }
16. -------------------------------------------------------------------------------------
17. public class SmsSender implements Sender {
18.
19. @Override
20. public void send() {
21. System.out.println("this is sms sender!");
22. }
23. }
24. -------------------------------------------------------------------------------------
25. public class SendSmsFactory implements Provider {
26.
27. @Override
28. public Sender produce() {
29. return new SmsSender();
30. }
31. }
1. public class SendMailFactory implements Provider {
2.
3. @Override
4. public Sender produce() {
5. return new MailSender();
6. }
7. }
8. -------------------------------------------------------------------------------------
9. public class Test {
10. public static void main(String[] args) {
11. Provider provider = new SendMailFactory();
12. Sender sender = provider.produce();
13. sender.send();
14. }
15. }
3、建造者模式(Builder)
工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的 Test 结合起来得到的。
1. public class Builder {
2. private List<Sender> list = new ArrayList<Sender>();
3.
4. public void produceMailSender(int count) {
5. for (int i = 0; i < count; i++) {
6. list.add(new MailSender());
7. }
8. }
9.
10. public void produceSmsSender(int count) {
11. for (int i = 0; i < count; i++) {
12. list.add(new SmsSender());
13. }
14. }
15. }
1. public class Builder {
2. private List<Sender> list = new ArrayList<Sender>();
3.
4. public void produceMailSender(int count) {
5. for (int i = 0; i < count; i++) {
6. list.add(new MailSender());
7. }
8. }
9.
10. public void produceSmsSender(int count) {
11. for (int i = 0; i < count; i++) {
12. list.add(new SmsSender());
13. }
14. }
15. }
1. public class TestBuilder {
2. public static void main(String[] args) {
3. Builder builder = new Builder();
4. builder.produceMailSender(10);
5. }
6. }
4、适配器设计模式
什么是适配器模式
一、
适配器模式也称为变压器模式,它是把一个类的接口转换成客户端所期望的另一种接口,从而使原本因接口不匹配而无法-起工作的两个类能够-起工作。适配类可以根据所传递的参数返还一个合适的实例给客户端。
二、
三、
适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。
主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。
(1)类的适配器模式
1. public class Source {
2. public void method1() {
3. System.out.println("this is original method!");
4. }
5. }
6. -------------------------------------------------------------
7. public interface Targetable {
8. /* 与原类中的方法相同 */
9. public void method1();
10. /* 新类的方法 */
11. public void method2();
12. }
13. public class Adapter extends Source implements Targetable {
14. @Override
15. public void method2() {
16. System.out.println("this is the targetable method!");
17. }
18. }
19.
20. public class AdapterTest {
21. public static void main(String[] args) {
22. Targetable target = new Adapter();
23. target.method1();
24. target.method2();
25. }
26. }
(2)对象的适配器模式
基本思路和类的适配器模式相同,只是将 Adapter 类作修改,这次不继承 Source 类,而是持有 Source 类的实例,以达到解决兼容性的问题。
1. public class Wrapper implements Targetable {
2. private Source source;
3.
4. public Wrapper(Source source) {
5. super();
6. this.source = source;
7. }
8.
9. @Override
10. public void method2() {
11. System.out.println("this is the targetable method!");
12. }
13.
14. @Override
15. public void method1() {
16. source.method1();
17. }
18. }
19. --------------------------------------------------------------
20. public class AdapterTest {
21.
22. public static void main(String[] args) {
23. Source source = new Source();
24. Targetable target = new Wrapper(source);
25. target.method1();
26. target.method2();
27. }
28. }
(3)接口的适配器模式
接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些。
此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。
5、装饰模式(Decorator)
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。
1. public interface Sourceable {
2. public void method();
3. }
4. ----------------------------------------------------
5. public class Source implements Sourceable {
6. @Override
7. public void method() {
8. System.out.println("the original method!");
9. }
10. }
11. ----------------------------------------------------
12. public class Decorator implements Sourceable {
13. private Sourceable source;
14. public Decorator(Sourceable source) {
15. super();
16. this.source = source;
17. }
18.
19. @Override
20. public void method() {
21. System.out.println("before decorator!");
22. source.method();
23. System.out.println("after decorator!");
24. }
25. }
26. ----------------------------------------------------
27. public class DecoratorTest {
28. public static void main(String[] args) {
29. Sourceable source = new Source();
30. Sourceable obj = new Decorator(source);
31. obj.method();
32. }
33. }
6、策略模式(strategy)
策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。
需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数。
策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。
因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可。
1. public interface ICalculator {
2. public int calculate(String exp);
3. }
4. ---------------------------------------------------------
5. public class Minus extends AbstractCalculator implements ICalculator {
6.
7. @Override
8. public int calculate(String exp) {
9. int arrayInt[] = split(exp, "-");
10. return arrayInt[0] - arrayInt[1];
11. }
12. }
13. ---------------------------------------------------------
14. public class Plus extends AbstractCalculator implements ICalculator {
15.
16. @Override
17. public int calculate(String exp) {
18. int arrayInt[] = split(exp, "\\+");
19. return arrayInt[0] + arrayInt[1];
20. }
21. }
22. --------------------------------------------------------
23. public class AbstractCalculator {
24. public int[] split(String exp, String opt) {
25. String array[] = exp.split(opt);
26. int arrayInt[] = new int[2];
27. arrayInt[0] = Integer.parseInt(array[0]);
28. arrayInt[1] = Integer.parseInt(array[1]);
29. return arrayInt;
30. }
31. }
1. public class StrategyTest {
2. public static void main(String[] args) {
3. String exp = "2+8";
4. ICalculator cal = new Plus();
5. int result = cal.calculate(exp);
6. System.out.println(result);
7. }
8. }
7、观察者模式(Observer)
什么是观察者模式
一、
二、
三、
观察者模式很好理解,类似于邮件订阅和 RSS 订阅,当我们浏览一些博客或 wiki 时,经常会看到 RSS 图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。
1. public interface Observer {
2. public void update();
3. }
4.
5. public class Observer1 implements Observer {
6. @Override
7. public void update() {
8. System.out.println("observer1 has received!");
9. }
10. }
11.
12. public class Observer2 implements Observer {
13. @Override
14. public void update() {
15. System.out.println("observer2 has received!");
16. }
17. }
18.
19. public interface Subject {
20. /*增加观察者*/
21. public void add(Observer observer);
22.
23. /*删除观察者*/
24. public void del(Observer observer);
25. /*通知所有的观察者*/
1. public void notifyObservers();
2.
3. /*自身的操作*/
4. public void operation();
5. }
6.
7. public abstract class AbstractSubject implements Subject {
8.
9. private Vector<Observer> vector = new Vector<Observer>();
10.
11. @Override
12. public void add(Observer observer) {
13. vector.add(observer);
14. }
15.
16. @Override
17. public void del(Observer observer) {
18. vector.remove(observer);
19. }
20.
21. @Override
22. public void notifyObservers() {
23. Enumeration<Observer> enumo = vector.elements();
24. while (enumo.hasMoreElements()) {
25. enumo.nextElement().update();
26. }
27. }
28. }
29.
30. public class MySubject extends AbstractSubject {
31.
32. @Override
33. public void operation() {
34. System.out.println("update self!");
35. notifyObservers();
36. }
37. }
38.
39. public class ObserverTest {
40. public static void main(String[] args) {
41. Subject sub = new MySubject();
42. sub.add(new Observer1());
43. sub.add(new Observer2());
44. sub.operation();
45. }
46. }