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

    1、什么是设计模式

    设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。

    一些简单的设计模式略过,如常量接口模式、标识类型模式。

    以下,将从最简单的设计模式开始讲起:

    2、单例模式 Singleton

        单例模式是指一个类只能拥有唯一的实例。为了保证这一点,我们必须要限制类的创建。即某个单例类,只可以实例化一次。那怎么才可以做到呢?

         实现思路如下:

    给需要单例的类声明私有的构造方法。这样就限制了其他类对此类的随意创建。

    在单例类内部,声明自己的静态成员变量,且实例化自己。由在当前类中,是可以访问自己的所有私有成员及方法的,所以,即使构造方法为私有也可以成功创建对象。

    一般情况下,再提供一个静态方法以返回创建的喻一对象。一般情况下,我们将此方法取名为newInstace,getInstance等,不过这并不是硬性的规定。

    示例代码如下:

    public class SingletonDemo { 
    
        //私有化构造方法 
    
        private SingletonDemo(){} 
    
        //声明静态私有成员变量 
    
        private static SingletonDemo demo; 
    
        //提供静态工厂方法 
    
        public static SingletonDemo getInstance(){ 
    
            if(demo==null){ 
    
                demo = new SingletonDemo(); 
    
            } 
    
            return demo; 
    
        } 
    
    }

    4、多例模式 Multition

    既然有单例,就会有多例。多例是指限定一个类的只能创建N(具体数量)个的设计模式。如以下性别类,就只能创建两个实例。实现思路是在本类中声明多个类的实例,并提供静态方法返回不同的实例即可:

    第一种实现:

    public class Gender { 
    
        private String sex; 
    
        private Gender(String sex){ 
    
            this.sex = sex; 
    
        } 
    
        //男性 
    
        private static Gender MALE; 
    
        //女性 
    
        private static Gender FEMALE; 
    
        public static Gender getMale(){ 
    
            if(MALE==null){ 
    
                MALE = new Gender("男"); 
    
            } 
    
            return MALE; 
    
        } 
    
        public static Gender getFemale(){ 
    
            if(FEMALE==null){ 
    
                FEMALE = new Gender("女"); 
    
            } 
    
            return FEMALE; 
    
        } 
    
    }
    第二种实现:   
    public class Gender { 
    
        private String sex; 
    
        private Gender(String sex){ 
    
            this.sex = sex; 
    
        } 
    
        //男性 
    
        private static Gender MALE; 
    
        //女性 
    
        private static Gender FEMALE; 
    
        static{//静态代码块中初始化 
    
            MALE = new Gender("男"); 
    
            FEMALE = new Gender("女"); 
    
        } 
    
        public static Gender getMale(){ 
    
            return MALE; 
    
        } 
    
        public static Gender getFemale(){ 
    
            return FEMALE; 
    
        } 
    
    }
    第三种实现:直接使用枚举
    public enum Gender{ 
    
        MALE("男"),FEMALE("女"); 
    
        private String sex; 
    
        private Gender(String sex){ 
    
            this.sex=sex; 
    
        } 
    
        @Override 
    
        public String toString() { 
    
            return sex; 
    
        } 
    
    }

    5、工厂方法模式Factory Method

    工厂方法指在一个类内部,提供一个静态方法,返回自己的实例或是其他类的实例。具体是返回自己的实例,还是返回其他类的实例,这个要看具体业务的需求。我们的数据连接池返回的就是其他对象的实例:

    public class FactoryDemo{ 
    
        private static Connection con; 
    
        static{ 
    
        //在此连接数据库 
    
        con = DriverManager.getConnection(…); 
    
    } 
    
    //提供一个静态工厂方法 
    
    public static Connection getConn(){ 
    
        return con; 
    
    } 
    
    }

    6、适配置器模式 Adapter

    一个接口,往往定义很多方法,但实现此接口的类,可能只需要几个方法。那么那些多余的方法,占据了我们大量的代码,将失去意义。那怎么才可以即省去一些无用的方法,又实现此接口呢?这就是适配置器模式。

    Awt开发中的Listener大量使用了此模式。如WindowListener和WindowAdapter。

    请见上面两个类(WindowListener和WindowAdapter)的源代码。

    7、装饰器设计模式(Decorator)也叫包装设计模式(Wrapper)

        如果一个类,即是某个类的子类,又拥有某个类的一个成员变量,则被叫做包装模式。 如:

    public Interface IA{} //定义一个接口 
    
    public class B implements IA{ //首先B是IA的子类 
    
        private IA ia;             //然后B拥有一个IA的成员变量。 
    
    }
    使用装饰器或是包装模式一般是为了增强类的功能。如增强某个方法等。

    8、代理模式 Proxy

    代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

    假设有一个Italk接口,有空的方法talk()(说话),所有的people对象都实现(implements)这个接口,实现talk()方法,前端有很多地方都将people实例化,执行talk方法,后来发现这些前端里有一些除了要说话以外还要唱歌(sing),那么我们既不能在Italk接口里增加sing()方法,又不能在每个前端都增加sing方法,我们只有增加一个代理类talkProxy,这个代理类里实现talk和sing方法,然后在需要sing方法的客户端调用代理类即可,代码如下:

    //定义接口 
    
    interface ITalk { 
    
        public void talk(String msg); 
    
    } 
    
    //定义一个代理,接收ITalk,并增加一个方法sing 
    
    class TalkProxy implements ITalk{ 
    
        private ITalk talker; 
    
        private String music; 
    
        public TalkProxy(ITalk talker,String music){ 
    
            this.talker=talker; 
    
            this.music = music; 
    
        } 
    
         
    
        @Override 
    
        public void talk(String msg) { 
    
            talker.talk(msg); 
    
            sing(); 
    
        } 
    
        //再多定义一个唱歌方法 
    
        private void sing(){ 
    
            System.err.println("正在唱:"+music); 
    
        } 
    
    } 
    
    //接口的一个实现类 
    
    class Tom implements ITalk{ 
    
        public void talk(String msg) { 
    
            System.err.println("正在说话:"+msg); 
    
        } 
    
    } 
    
    //测试调用 
    
    public class ProxyDemo{ 
    
        public static void main(String[] args) { 
    
            TalkProxy proxy = new TalkProxy(new Tom(),"十里香"); 
    
            proxy.talk("Hello"); 
    
        } 
    
    }


    9、动态代理 Dync Proxy

        在JDK中,Proxy类和InvocationHandler可以在不添加任何代码的情况下增强某个方法:

    package cn.itcast.pattern; 
    
    import java.lang.reflect.InvocationHandler; 
    
    import java.lang.reflect.Method; 
    
    import java.lang.reflect.Proxy; 
    
    import java.util.ArrayList; 
    
    import java.util.List; 
    
    //测试代码 
    
    public class DyncProxyDemo { 
    
        public static void main(String[] args) { 
    
            List list =(List) MyProxy.getProxy(new ArrayList()); 
    
            list.add("Hello"); 
    
        } 
    
    } 
    
    //书写代理类 
    
    class MyProxy implements InvocationHandler{ 
    
        //声明被代理之前的对象 
    
        private Object src; 
    
        //私有构造方法 
    
        private MyProxy(Object src){ 
    
            this.src=src; 
    
        } 
    
        //提供一个静态方法以返回被代理以后的对象 
    
        public static Object getProxy(Object src){ 
    
            Object dest = null;//被代理以后的对象 
    
            try{ 
    
                //处理代理的核心代码 
    
                dest = Proxy.newProxyInstance(MyProxy.class.getClassLoader(), 
    
                            src.getClass().getInterfaces(), 
    
                            new MyProxy(src)); 
    
            }catch(Exception e){ 
    
                throw new RuntimeException(e.getMessage(),e); 
    
            } 
    
            return dest; 
    
        } 
    
        //拦截方法 
    
        public Object invoke(Object proxy, Method method, Object[] args) 
    
                throws Throwable { 
    
            System.err.println("正直执行方法:"+method.getName()); 
    
            Object oo = method.invoke(src, args); 
    
            return oo; 
    
        } 
    
         
    
    }


    10、观察者模式Observer

        观察者模式又叫做发布订阅模式。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。如Awt中的监听器Listener都是采用了种模式。

        在此种模式下,观察者只是一个接口,即定义一个规范,具体的实现应该是客户端完成。就像Swing中的注册一个监听器一样如:

    JFrame frame = new Jframe();//声明被观察,被监听者对象

    frame.addWindowListener(new WindowListener(){…});//添加一个实现WindowListener的观察者

    frame.setVisible(true);    //执行一些后续的操作,只要注册了观察者,就会被观察者所监听到

    示例代码如下:

     

    public class ObserverDemo { 
    
        public static void main(String[] args) { 
    
            //杰克逊对象 
    
            Singer jackson = new Singer(); 
    
            //注册观察者 
    
            jackson.addListener(new SingListener() { 
    
                public void listener(Singer singer) { 
    
                    System.err.println("监听到了手的正在唱歌。。。。"); 
    
                } 
    
            }); 
    
            //唱歌 
    
            jackson.sing(); 
    
        } 
    
    } 
    
    //设置一个监听器接口-监听谁在唱歌 
    
    interface SingListener{ 
    
        public void listener(Singer singer); 
    
    } 
    
    //一个可能的被监听者 
    
    class Singer{ 
    
        //声明观察者 
    
        private SingListener listener; 
    
        public void addListener(SingListener sl){ 
    
            this.listener=sl; 
    
        } 
    
        public void sing(){ 
    
            //判断是否有观察者 
    
            if(this.listener!=null){ 
    
                this.listener.listener(this); 
    
            } 
    
            System.err.println("歌手正在唱歌"); 
    
        } 
    
    }
     

    给观察者添加一个观察事件对象,SingEvent,以便于解藕:

    完整的示例代码如下:

    package cn.itcast.pattern; 
    
    //测试代码 
    
    public class ObserverDemo { 
    
        public static void main(String[] args) { 
    
            Singer jackson = new Singer(); 
    
            jackson.addListener(new SingListener() { 
    
                public void listener(SingEvent event) { 
    
                    System.err.println("歌手是:"+event.getSource()); 
    
                } 
    
            }); 
    
            jackson.sing(); 
    
        } 
    
    } 
    
    //设置一个监听器接口-监听谁在唱歌 
    
    interface SingListener{ 
    
        public void listener(SingEvent event); 
    
    } 
    
    //设计一个事件对象 
    
    class SingEvent{ 
    
        //接收事件对象,即被观察者 
    
        private Object source; 
    
        public SingEvent(Object source){ 
    
            this.source=source; 
    
        } 
    
        public Object getSource() { 
    
            return source; 
    
        } 
    
    } 
    
    //一个可能的被监听者 
    
    class Singer{ 
    
        //声明观察者 
    
        private SingListener listener; 
    
        public void addListener(SingListener sl){ 
    
            this.listener=sl; 
    
        } 
    
        public void sing(){ 
    
            //判断是否有观察者 
    
            if(this.listener!=null){ 
    
                this.listener.listener(new SingEvent(this)); 
    
            } 
    
            System.err.println("歌手正在唱歌"+this); 
    
        } 
    
    }
     

    11、策略模式Strategy

    策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

    策略模式的组成

    -抽象策略角色: 策略类,通常由一个接口或者抽象类实现。

    -具体策略角色:包装了相关的算法和行为。

    -环境角色:持有一个策略类的引用,最终给客户端调用。

    package cn.itcast.pattern; 
    
    /** 
    
     * 策略模式 
    
    */ 
    
    public class StrategyDemo { 
    
        public static void main(String[] args) { 
    
            Context ctx = new Context(new JavaProgrammer()); 
    
            ctx.doSth(); 
    
        } 
    
    } 
    
    //设计一个公共的接口 
    
    interface IStrategy{ 
    
        public void doSth(); 
    
    } 
    
    //分别书写多个实现类,有不同的实现策略 
    
    class JavaProgrammer implements IStrategy{ 
    
        public void doSth() { 
    
            System.err.println("写Java代码"); 
    
        } 
    
    } 
    
    class PhpProgrammer implements IStrategy{ 
    
        public void doSth() { 
    
            System.err.println("写PHP代码"); 
    
        } 
    
    } 
    
    //实现策略类 
    
    class Context{ 
    
        private IStrategy strategy; 
    
        public Context(IStrategy strategy){ 
    
            this.strategy = strategy; 
    
        } 
    
        //具体调用 
    
        public void doSth(){ 
    
            this.strategy.doSth(); 
    
        } 
    
    }
     

    12、门面设计模式

    门面设计模式的结构:

    没有门面设计模式的调用方法:

    有了门面设计模式的类框架图如下:即由原来的客户端一一调用每一个系统,修改成一使用一个统一中调用:

    具体实现代码略。

     

    13、命令模式Command

    在软件系统中,"行为请求者"与"行为实现者"通常呈现一种"紧耦合"。但在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式(Command Pattern)

     

    示例代码如下:

    package cn.itcast.pattern; 
    
    public class CommandDemo { 
    
        public static void main(String[] args) { 
    
            //命令的接收者只有一个 
    
            Receiver receiver = new Receiver(); 
    
            //定义命令的执行者 
    
            Invoker invoker = new Invoker(); 
    
            //通过Command类具体通知命令的接收者做什么工作 
    
            invoker.setCommand(new CommandA(receiver)); 
    
            invoker.execute(); 
    
            //再设置第二个命令 
    
            invoker.setCommand(new CommandB(receiver)); 
    
            invoker.execute(); 
    
        } 
    
    } 
    
    //定义命令 
    
    abstract class Command{ 
    
        //定义接收命令对象 
    
        protected Receiver receiver; 
    
        public Command(Receiver rec){ 
    
            this.receiver=rec; 
    
        } 
    
        public abstract void execute(); 
    
    } 
    
    //指定接收者的工作 
    
    class Receiver{ 
    
        public void actionA(){ 
    
            System.err.println("做第一件事"); 
    
        } 
    
        public void actionB(){ 
    
            System.err.println("做第二件事"); 
    
        } 
    
    } 
    
    //执行者 
    
    class Invoker{ 
    
        //接收一个命令 
    
        private Command command; 
    
        public void setCommand(Command cmd){ 
    
            this.command = cmd; 
    
        } 
    
        //执行命令 
    
        public void execute(){ 
    
            command.execute(); 
    
        } 
    
    } 
    
    //定义两个具体的命令 
    
    class CommandA extends Command{ 
    
        public CommandA(Receiver rec) { 
    
            super(rec); 
    
        } 
    
        @Override 
    
        public void execute() { 
    
            this.receiver.actionA(); 
    
        } 
    
    } 
    
    //定义两个具体的命令 
    
    class CommandB extends Command{ 
    
        public CommandB(Receiver rec) { 
    
            super(rec); 
    
        } 
    
        @Override 
    
        public void execute() { 
    
            this.receiver.actionB(); 
    
        } 
    
    }
     

    14、原型模式Prototype

    用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

    Prototype原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。

    它主要面对的问题是:"某些结构复杂的对象"的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。

      如何使用?

      因为Java中的提供clone()方法来实现对象的克隆,所以Prototype模式实现一下子变得很简单。

    代码略。

     

    15、亨元模式flyweight

    可以理解成为轻量级模式,是一种软件设计模式。

    面向对象的思想很好地解决了抽象性的问题,一般也不会出现性能上的问题。但是在某些情况下,对象的数量可能会太多,从而导致了运行时的代价。那么我们如何去避免大量细粒度的对象,同时又不影响客户程序使用面向对象的方式进行操作?

    见下面的代码:

    //使用Integer对象的示例 
    
            Integer b1 = 100; 
    
            Integer b2 = 100; 
    
            System.err.println(b1==b2); //true 
    
            //由于大量细粒度的对象出现在128以下,所以,下现的值为false 
    
            Integer b3 = 128; 
    
            Integer b4 = 128; 
    
        System.err.println(b3==b4); //false
     

    16、总结

        在实际的开发中,单例、多例、工厂、适配置器、代理、装饰、包装是经常使用的发模式,其他模式只需要了解就可以了。

  • 相关阅读:
    Linux之文件处理命令
    Linux基础命令
    rip实验
    Linux基础之磁盘分区
    mysql安装
    centos Apache、php、mysql默认安装路径
    You probably tried to upload too large file. Please refer to documentation for ways to workaround this limit.
    Wrong permissions on configuration file, should not be world writable!
    机器会学习么 学习总结
    实验 5 Spark SQL 编程初级实践
  • 原文地址:https://www.cnblogs.com/starzy/p/10376606.html
Copyright © 2011-2022 走看看