zoukankan      html  css  js  c++  java
  • 设计模式基础

    一、设计模式简介

    设计模式是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。

    使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

    总结:简单地说设计模式就是一些常用编码规范的总结,是一种思想,如果你是大牛,也可以自己写一种设计模式供大家使用

    二、设计模式四大要素

    模式名称 :以一个恰当的词来描述模式的问题、解决方案和效果。

    问题 :描述应该在何时使用设计模式。

    解决方案 :提供设计问题的抽象描述和怎样用一个具有一般意义的元素组合(类或对象)来解决这个问题。

    效果:描述设计模式应用的效果及使用设计模式应该权衡的问题。

    三、设计模式六大原则(武功秘籍,懂了秘籍自己就可以根据秘籍去创造自己的设计模式,不必拘泥于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 }
  • 相关阅读:
    Android -- ConditionVariable
    Android -- startActivityForResult和setResult
    StringTokenizer
    Android -- java代码设置margin
    Android -- DisplayMetrics
    Android -- TypedArray
    Android -- 屏幕亮度
    Java assert
    Android -- com.android.providers.media,external.db
    Inno Setup入门(十)——操作注册表
  • 原文地址:https://www.cnblogs.com/leeSmall/p/8620342.html
Copyright © 2011-2022 走看看