一、设计模式简介
设计模式是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
总结:简单地说设计模式就是一些常用编码规范的总结,是一种思想,如果你是大牛,也可以自己写一种设计模式供大家使用
二、设计模式四大要素
模式名称 :以一个恰当的词来描述模式的问题、解决方案和效果。
问题 :描述应该在何时使用设计模式。
解决方案 :提供设计问题的抽象描述和怎样用一个具有一般意义的元素组合(类或对象)来解决这个问题。
效果:描述设计模式应用的效果及使用设计模式应该权衡的问题。
三、设计模式六大原则(武功秘籍,懂了秘籍自己就可以根据秘籍去创造自己的设计模式,不必拘泥于23中设计模式)
1. 开闭原则
开放封闭有两个含义,一个是对于拓展是开放的,另一个是对于修改是关闭的。在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。
解决方案: 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
总结:
面向对象设计/编程 终极目标(实现开闭原则)
一个是对于拓展是开放的,另一个是对于修改是关闭的
尽量不要修改已有代码
2. 单一职责原则
通俗讲就是我们不要让一个类承担过多的职责。如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到破坏。
解决方案: 分别建立两个类C1、C2,使类C1完成职责A,C2完成职责B。这样,当修改类C1时,不会使职责B发生故障风险;同理,当修改类C2时,也不会使职责A发生故障风险。
总结:
不要让一个类承担过多的职责
3. 里氏替换原则
里氏代换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常。
解决方案: 当使用继承时,遵循里氏替换原则。类B继承类A时,除添加新的方法完成新增功能外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法。
总结:
继承父类后,尽量不要重写或者重载父类的方法。
4. 依赖倒转原则
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。 类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
解决方案: 将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
总结:
通过抽象或者接口来实现类与类之间的依赖关系。
5. 接口隔离原则
建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
解决方案: 将臃肿的接口拆分为独立的几个接口,实现类分别与他们需要的接口建立依赖关系。
总结:
建立单一接口,不要建立庞大/臃肿的接口
6. 迪米特法则
迪米特法则也称为最少知道原则,一个实体应该尽可能少的与另外一个实体发生相互作用(依赖关系)。
解决方案: 尽可能降低类之间的耦合
总结:
只提供方法给外部调用,不要让外部知道你是怎么做的
四、设计模式分类
创建型设计模式:
创建型模式抽象实例化过程,在什么对象被创建、谁创建它、它是怎么被创建的以及何时创建这些方面给予你很大的灵活性——主要处理对象的创建,实例化对象。
结构型设计模式:
结构型模式涉及到如何组合类和对象以获得更大的结构,采用继承机制来组合接口或实现——处理类或对象的组合以获得更庞大的功能。
行为型设计模式:
行为模式涉及到算法和对象间职责的分配,不仅描述对象或类的模式,还描述它们之间的通信模式——处理对象之间的交互
五、常用的六种设计模式(招式,设计模式六大原则的实现)
1. 创建型模式之【单例模式】
问题 对于某些场景,确保一个类只有一个实例对象是很重要的,并且这个实例是易于被访问的。
解决方案:将实例化操作隐藏在一个类中,由这个类来保证实例的创建和唯一性。
单例模式 饿汉(一开始就创建实例)
1 package com.study.demo1;
2 /**
3 *
4 * @author lgs
5 * @redame 单例模式 饿汉(一开始就创建实例)
6 */
7 public class SingletonObjectA {
8 private static SingletonObjectA instance = new SingletonObjectA();
9
10 private SingletonObjectA(){}
11
12 public static SingletonObjectA getInstance(){
13 return instance;
14 }
15 }
单例模式 饱汉(需要的时候才创建实例)
1 package com.study.demo1;
2 /**
3 *
4 * @author lgs
5 * @redame 单例模式 饱汉(需要的时候才创建实例)
6 */
7 public class SingletonObjectB {
8 private static volatile SingletonObjectB instance = null;
9
10 private SingletonObjectB(){}
11
12 public static SingletonObjectB getInstance(){
13 if(instance==null){
14 synchronized(instance){
15 if(instance == null){
16 instance = new SingletonObjectB();
17 }
18 }
19 }
20 return instance;
21 }
22 }
主程序入口:
1 public class Demo1 {
2 public static void main(String[] args) {
3 SingletonObjectA object1 = SingletonObjectA.getInstance();
4
5 SingletonObjectA object2 = SingletonObjectA.getInstance();
6
7 System.out.println(object1);
8 System.out.println(object2);
9 }
10 }
2. 创建型模式之【工厂模式】
问题:当一个类无法确定要创建哪种类的对象,或者需要通过子类来确定具体对象的创建时。
解决方案:创建一个创建对象的工厂,工厂在程序执行过程中具体决定创建哪个对象。
发送消息的接口:
1 package com.study.demo2;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public interface Sender {
8
9 public void send();
10 }
使用邮件发送消息:
1 package com.study.demo2;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public class MailSender implements Sender {
8
9 @Override
10 public void send() {
11 System.out.println("Use the email sender message.");
12 }
13
14 }
使用SMS发送消息:
1 package com.study.demo2;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public class SmsSender implements Sender {
8
9 @Override
10 public void send() {
11 System.out.println("Use the SMS sender messages.");
12 }
13
14 }
使用微信发送消息:
1 package com.study.demo2;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public class WechatSender implements Sender {
8
9 @Override
10 public void send() {
11 System.out.println("Use the Wechat sender messages.");
12 }
13
14 }
普通工厂模式:
1 package com.study.demo2;
2 /**
3 *
4 * @author lgs
5 * @redame 普通工厂模式
6 */
7 public class MessageFactoryA {
8 public static String MAIL="MAIL";
9 public static String SMS="SMS";
10 public static String WE_CHAT="WE_CHAT";
11
12 public Sender product(String type){
13 if(MessageFactoryA.MAIL.equals(type)){
14 return new MailSender();
15 } else if(MessageFactoryA.SMS.equals(type)){
16 return new SmsSender();
17 } else if(MessageFactoryA.WE_CHAT.equals(type)){
18 return new WechatSender();
19 }
20 return null;
21 }
22 }
工厂方法模式:
1 package com.study.demo2;
2 /**
3 *
4 * @author lgs
5 * @redame 工厂方法模式
6 */
7 public class MessageFactoryB {
8
9 public Sender productMail(){
10 return new MailSender();
11 }
12 public Sender productSMS(){
13 return new SmsSender();
14 }
15 public Sender productWechat(){
16 return new WechatSender();
17 }
18 }
主程序入口:
1 package com.study.demo2;
2
3 /**
4 *
5 * @author lgs
6 */
7 public class Demo2 {
8 public static void main(String[] args) {
9 // 普通工厂模式
10 // MessageFactoryA factory = new MessageFactoryA();
11 // Sender sender = factory.product(MessageFactoryA.WE_CHAT);
12 // sender.send();
13 // 工厂方法模式
14 MessageFactoryB factory = new MessageFactoryB();
15 Sender sender = null;
16 if (MessageFactoryA.WE_CHAT.equals("1")) {
17 sender = factory.productWechat();
18 }
19
20 }
21 }
3. 结构型模式之【适配器模式】
问题:
有时,为复用而设计的工具箱类不能够被复用的原因,仅仅是因为它的接口与专业应用领域所需要的接口不匹配。
解决方案:
应用通过适配器调用接口,由适配器使得工具箱类可以被使用。
总结:把不同的功能集成到适配器。类似通过转换器把香港iPhone的充电器插头和大陆的iPhone的充电器插头一起使用
3.1 类适配器模式:
1 package com.study.demo3.classType;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public class Source {
8
9 public void method1(){
10 System.out.println("一个普通方法实现.");
11 }
12 }
1 package com.study.demo3.classType;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public interface Targetable {
8
9 //与原类中的方法相同
10 public void method1();
11
12 //新类中的方法
13 public void method2();
14 }
1 package com.study.demo3.classType;
2 /**
3 *
4 * @author lgs
5 * @类适配器模式:通过继承Source类,Targetable接口的实现类拥有了Source的方法.
6 */
7 public class SpecialAdapter extends Source implements Targetable {
8
9 @Override
10 public void method2() {
11 System.out.println("这是一个特殊方法实现.");
12 }
13
14 }
主程序入口:
1 public class Demo31 {
2
3 public static void main(String[] args) {
4 Targetable target = new SpecialAdapter();
5 target.method1();
6 target.method2();
7 }
8 }
3.2 对象适配器模式:
1 package com.study.demo3.objectType;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public class Source {
8
9 public void method1(){
10 System.out.println("一个普通方法实现.");
11 }
12 }
1 package com.study.demo3.objectType;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public interface Targetable {
8
9 //与原类中的方法相同
10 public void method1();
11
12 //新类中的方法
13 public void method2();
14 }
1 package com.study.demo3.objectType;
2 /**
3 *
4 * @author lgs
5 * @对象适配器模式
6 */
7 public class SpecialAdapter implements Targetable {
8
9 /**
10 * 可匹配Source的子类
11 **/
12 private Source source;
13 public SpecialAdapter(Source source){
14 super();
15 this.source = source;
16 }
17 @Override
18 public void method1() {
19 source.method1();
20 }
21
22 @Override
23 public void method2() {
24 System.out.println("这是一个特殊方法实现.");
25 }
26
27 }
主程序入口:
1 public class Demo32 {
2 public static void main(String[] args) {
3
4 Targetable adapter = new SpecialAdapter(new Source());
5 adapter.method1();
6 adapter.method2();
7 }
8 }
4. 结构型模式之【代理模式】
问题:
对象的访问需要被控制,不允许其他对象任意访问此对象接口。
解决方案:
代理类开放接口提供访问,所有访问由代理类决定具体的调用。
总结:
类似于经纪人和艺人的关系,艺人的任何事情都要先经过经纪人的许可才能去做
1 package com.study.demo4;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public abstract class AbstractObject {
8
9 //代理方法
10 public abstract void operation();
11 }
1 package com.study.demo4;
2 /**
3 *
4 * @author lgs
5 * @真正做事的人
6 *
7 */
8 public class RealObject extends AbstractObject {
9
10 @Override
11 public void operation() {
12 System.out.println("具体执行任务.");
13 }
14
15 }
1 package com.study.demo4;
2 /**
3 *
4 * @author lgs
5 * @代理人
6 *
7 */
8 public class ProxyObject extends AbstractObject {
9
10 RealObject realObject = new RealObject();
11 @Override
12 public void operation() {
13 System.out.println("执行任务前, 做一些什么事情.");
14 realObject.operation();
15
16 }
17
18 }
主程序入口:
1 public class Demo4 {
2 public static void main(String[] args) {
3 AbstractObject obj = new ProxyObject();
4 obj.operation();
5 }
6 }
5. 行为模式之【观察者模式】
问题:
将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象间的一致性,然而维护对象间的一致性可能导致各类之间的紧密耦合,这样将降低它们的可重用性。
解决方案:
观察者模式建立一个目标和任意个依赖它的观察者,一旦目标状态发生改变,所有的观察者都得到通知。
1 package com.study.demo5;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public interface Observer {
8 public void update();
9 }
1 package com.study.demo5;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public class ObserverA implements Observer {
8
9 @Override
10 public void update() {
11 System.out.println("观察者A观察到对象的变化.");
12 }
13
14 }
1 package com.study.demo5;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public class ObserverB implements Observer {
8
9 @Override
10 public void update() {
11 System.out.println("观察者B观察到对象的变化.");
12 }
13
14 }
1 package com.study.demo5;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public interface Subject {
8 //本身的任务调用
9 public void operation();
10
11 }
1 package com.study.demo5;
2
3 import java.util.Vector;
4
5 /**
6 *
7 * @author lgs
8 *
9 */
10 public abstract class AbstractSubject implements Subject {
11
12 private Vector<Observer> observerList = new Vector<Observer>();
13
14 public void add(Observer observer) {
15 observerList.add(observer);
16 }
17
18 public void del(Observer observer) {
19 observerList.remove(observer);
20 }
21
22 public void notifyObservers() {
23 for (Observer observer : observerList) {
24 observer.update();
25 }
26 }
27 }
1 package com.study.demo5;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public class MySubject extends AbstractSubject {
8
9 @Override
10 public void operation() {
11 System.out.println("执行方法, 状态修改. ");
12 //通知所有观察者
13 notifyObservers();
14 }
15
16 }
主程序入口:
1 public class Demo5 {
2 public static void main(String[] args) {
3 AbstractSubject subject = new MySubject();
4 subject.add(new ObserverA());
5 subject.add(new ObserverB());
6 subject.operation();
7 }
8 }
6. 行为模式之【策略模式】
问题:
开发中常见的情况:实现某功能可以有多种算法或者策略,可根据实际情况选择不同的算法或策略来完成该功能。如果将所有算法或策略都封装在一个类中,提供不同方法来实现,这个类就变得臃肿,而且新增算法或策略时,需要修改封装算法类的源码。
解决方案:
使用不同类来封装不同的算法
1 package com.study.demo6;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public interface MemberStrategy {
8 /**
9 * 计算图书的价格
10 * @param booksPrice 图书的原价
11 * @return 计算出打折后的价格
12 */
13 public double calcPrice(double booksPrice);
14 }
1 package com.study.demo6;
2 /**
3 *
4 * @author lgs 6 *
7 */
8 public class AdvancedMemberStrategy implements MemberStrategy {
9
10 @Override
11 public double calcPrice(double booksPrice) {
12 System.out.println("高级会员8折");
13 return booksPrice * 0.8;
14 }
15
16 }
1 package com.study.demo6;
2 /**
3 *
4 * @author lgs 6 *
7 */
8 public class IntermediateMemberStrategy implements MemberStrategy {
9
10 @Override
11 public double calcPrice(double booksPrice) {
12 System.out.println("中级会员9折");
13 return booksPrice * 0.9;
14 }
15
16 }
1 package com.study.demo6;
2 /**
3 *
4 * @author lgs 6 *
7 */
8 public class PrimaryMemberStrategy implements MemberStrategy {
9
10 @Override
11 public double calcPrice(double booksPrice) {
12 System.out.println("初级会员没有折扣");
13 return booksPrice;
14 }
15
16 }
1 package com.study.demo6;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public class Price {
8 //持有一个具体的策略对象
9 private MemberStrategy strategy;
10
11 /**
12 * @param strategy
13 */
14 public Price(MemberStrategy strategy) {
15 super();
16 this.strategy = strategy;
17 }
18
19 /**
20 * 计算图书的价格
21 * @param booksPrice 图书的原价
22 * @return 计算出打折后的价格
23 */
24 public double quote(double booksPrice){
25 return this.strategy.calcPrice(booksPrice);
26 }
27 }
主程序入口:
1 package com.study.demo6;
2 /**
3 *
4 * @author lgs
5 *
6 */
7 public class Demo6 {
8 public static void main(String[] args) {
9 //选择并创建需要使用的策略对象
10 MemberStrategy strategy = new AdvancedMemberStrategy();
11 //创建环境
12 Price price = new Price(strategy);
13 //计算价格
14 double quote = price.quote(300);
15 System.out.println("图书的最终价格为:" + quote);
16 }
17 }