设计模式(主要java)

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

下面主要来自网上我看到的解释的比较简洁易懂的例子的组合。常用的设计模式,一些不常用的我就没说。 

单例模式

//饿汉式单例类.在类初始化时,已经自行实例化 
public class Singleton1 {
    //私有的默认构造子
    private Singleton1() {}
    //已经自行实例化 
    private static final Singleton1 single = new Singleton1();
    //静态工厂方法 
    public static Singleton1 getInstance() {
        return single;
    }
}



//懒汉式单例类.在第一次调用的时候实例化 
public class Singleton2 {
    //私有的默认构造子
    private Singleton2() {}
    //注意,这里没有final    
    private static Singleton2 single=null;
    //静态工厂方法 
    public synchronized  static Singleton2 getInstance() {
         if (single == null) {  
             single = new Singleton2();
         }  
        return single;
    }

 

        String name = null;

    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public void printInfo() {  
        System.out.println("the name is " + name);  
    }  

public class TMain {
	public static void main(String[] args){
		TestStream ts1 = Singleton2.getInstance();
		ts1.setName("jason");
		TestStream ts2 = Singleton2.getInstance();
		ts2.setName("0539");
		
		ts1.printInfo();
		ts2.printInfo();
		
		if(ts1 == ts2){
			System.out.println("创建的是同一个实例");
		}else{
			System.out.println("创建的不是同一个实例");
		}
	}
}





工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,
达到提高灵活性的目的。

况下你可以考虑使用工厂模式:
1) 当客户程序不需要知道要使用对象的创建过程。
2) 客户程序使用的对象存在变动的可能,或者根本就不知道使用哪一个具体的对象。

我觉得一般最有用的就两种:静态工厂方法模和抽象工厂模式

凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。

创建二者的共同接口

1.  public interface Sender {  

2.      public void Send();  

3.  }  

其次,创建实现类:

1.  public class MailSender implements Sender {  

2.      @Override  

3.      public void Send() {  

4.          System.out.println("this is mailsender!");  

5.      }  

6.  }  

1.  public class SmsSender implements Sender {  

2.    

3.      @Override  

4.      public void Send() {  

5.          System.out.println("this is sms sender!");  

6.      }  

7.  }  

创建工厂类

1.  public class SendFactory {  

2.        

3.      public static Sender produceMail(){  

4.          return new MailSender();  

5.      }  

6.        

7.      public static Sender produceSms(){  

8.          return new SmsSender();  

9.      }  

10.}  

测试

1.  public class FactoryTest {  

2.    

3.      public static void main(String[] args) {      

4.          Sender sender = SendFactory.produceMail();  

5.          sender.Send();  

6.      }  

7.  }  

静态工厂方法模式,将方法置为静态的,不需要创建实例,直接调用即可

工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则。

 

创建二者的共同接口

4.  public interface Sender {  

5.      public void Send();  

6.  }  

其次,创建实现类:

7.  public class MailSender implements Sender {  

8.      @Override  

9.      public void Send() {  

10.          System.out.println("this is mailsender!");  

11.      }  

12.  }  

8.  public class SmsSender implements Sender {  

9.    

10.    @Override  

11.    public void Send() {  

12.        System.out.println("this is sms sender!");  

13.    }  

14.}  

上面都一样

提供一个工厂接口:

1.  public interface Provider {  

2.      public Sender produce();  //该函数返回类型是Sender

3.  }  

 

 

两个工厂类:

[java] view plaincopy

1.  public class SendMailFactory implements Provider {  

2.        

3.      @Override  

4.      public Sender produce(){  

5.          return new MailSender();  

6.      }  

7.  }  

[java] view plaincopy

1.  public class SendSmsFactory implements Provider{  

2.    

3.      @Override  

4.      public Sender produce() {  

5.          return new SmsSender();  

6.      }  

7.  }  

测试类:

 

1.  public class Test {  

2.    

3.      public static void main(String[] args) {  

4.          Provider provider = new SendMailFactory();  

5.          Sender sender = provider.produce();  

6.          sender.Send();  

7.      }  

8.  }  

抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。(比如这里如果想添加一个PicSender的功能,只需要先增加一个public class PicSender implements Sender 这个实现类,然后 增加一个工厂类public class SendPicFactory implements Provider。  而不需要修改原来的工厂))

用的时候,先new一个工厂类,实现Provider接口,再用这个工厂中的自带的函数创建一个Sender类,就OK

 

这里提一下

享元模式(Flyweight

享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。

当一个客户端请求时,工厂需要检查当前对象池中是否有符合条件的对象,如果有,就返回已经存在的对象,如果没有,则创建一个新对象。节省了空间,减少了实例的数量。是本地内存资源节省方案。

具体怎么就不说了。对分布式可能没啥用。对单机提升性能可能有用。

建造者模式

将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

 [构建与表示分离,同构建不同表示]

与抽象工厂的区别:在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者联系的,指导者联系建造者最后得到产品。即建造模式可以强制实行一种分步骤进行的建造过程

简单地说,就好象我要一座房子住,可是我不知道怎么盖(简单的砌墙,层次较低),也不知道怎么样设计(建几个房间,几个门好看,层次较高),于是我需要找一帮民工,他们会砌墙,还得找个设计师,他知道怎么设计,我还要确保民工听设计师的领导,而设计师本身也不干活,光是下命令,这里砌一堵墙,这里砌一扇门,这样民工开始建设,最后,我可以向民工要房子了。在这个过程中,设计师是什么也没有,除了他在脑子里的设计和命令,所以要房子也是跟民工要,记住了!


1,定义工人接口
,就是能够完成建造房子任务的人的通用要求。

java 代码

 

1.  // 工人接口,定义了各个工人所要进行的工所作。他们负责进行具体部件如窗户,地板的建造。

2.  // 同时因为房子是民工建的,因此建设完成后由他把房子递交回房主

3.  public interface Builder {  

4.      

5.    public  void makeWindow();  

6.    

7.    public  void makeFloor();  

8.    

9.    public  Room  getRoom();  

10. }  


2,定义设计师
,他的职责是指挥房主指派给他的工人按照自己的设计意图建造房子。

java 代码

 

1.  // 设计师。他知道房子应该怎么设计,但他不会自己去建造,而是指挥民工按一定流程去建造。  

2.  public class Designer {  

3.    private Builder builder;

4.      Public Designer(Builder builder){

5.      this.builder = builder;

6.  }

7.    // 指挥民工进行工作  

8.    public void order(Builder builder) {  

9.      builder.makeWindow();  

10.     builder.makeFloor();  

11.   }  

12. 


3,民工
,他负责具体事物的实施。

1.  // 民工。负责进行具体部件如窗户,地板的建造。

2.  //同时因为房子是民工建的,因此建设完成后由他把房子递交回房主  

3.  public class Mingong  implements Builder {  

4.    private  String window="";  

5.    private  String floor="";  

6.      

7.    public  void makeWindow() {  

8.      window=new String("window");  

9.    }  

10.   

11.   public  void makeFloor(){  

12.     floor=new String("floor");  

13.   }  

14.    

15.   // 回交房子给房主  

16.   public  Room  getRoom() {  

17.     if((!window.equals(""))&&(!floor.equals(""))) {  

18.       System.out.println("room ready!");  

19.       return new Room();  

20.     }  

21.     else return null;  

22.   }  

23. }  


4,房主
,就是雇人,收房。

1.   

2.  // 房主。房主的任务就是聘请一个民工,一个设计师,同时把民工给设计师指挥,督促设计师开展工作。最后从民工手上收房。    

3.  public class Client {    

4.      

5.    public static void main(String[] args) {    

6.       Builder mingong = new Mingong();    

7.       Designer  designer = new  Designer();    

8.       designer.order(mingong);    

9.       mingong.getRoom();    

10.   }    

11. 

 

想了想,如果把getRoom()方法放到Director里面,那不就成了类Proxy模式了吗? 

还是以上面的这个建房的场景说事吧。如果我向Director要房子,那么我就不知道他是否用我雇用的民工来干活,也许他私下又雇了其他的人,而不用我雇的人。也就是彻头彻尾的代理了。 

之所以要向Mingong要,是为了保证东西是由我亲自选定并信任的人来完成实际工作的

 

原型模式 

有的时候,我们需要一个实例时,并且,当创建一个实例的过程比较复杂或者说是昂贵时,

比如,创建实例的构造函数非常的复杂,在执行这个构造函数时会消耗较长的时间,

同时呢,这个构造函数中的一些信息又没有什么变化

(也就是说创建第一个实例时初始化信息是这样的,创建第二个实例时初始化信息还是还是这样的),

那么直接使用 new 来创建这样一个实例就显得太昂贵了,

最好的解决方法,并不是使用 new 来实例化一个对象,

在Java中,复制对象是通过clone()实现的,先创建一个原型类:

1.  public class Prototype implements Cloneable {  

2.    

3.      public Object clone() throws CloneNotSupportedException {  

4.          Prototype proto = (Prototype) super.clone();  

5.          return proto;  

6.      }  

7.  }  

很简单,一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称

 

// loneable接口并覆盖clone()方法

class ConcretePrototype01 implements Cloneable {

  private String name;

  public ConcretePrototype01(String name) {          //构造函数

    this.name = name;

  }

 

  public void getName() {

    System.out.println(name);

  }

  //覆盖Object基类中的clone()方法,并扩大该方法的访问权限,具体化返回本类型

  public ConcretePrototype01 clone() {               //返回类型是本类

    ConcretePrototype01 proto = null;   //新建一个本类的对象

          proto = (ConcretePrototype01) super.clone(); 

//如果不加 (ConcretePrototype01) ,则是object类型

    return proto;  //返回这个本类

  }

 

//测试类

public class Client {

  public static void main(String[] args) {

    ConcretePrototype01 prototype01 = new ConcretePrototype01("蚂蚁 ...");

    prototype01.getName();

 

    //通过clone获得一个拷贝

    ConcretePrototype01 fromClone01 = prototype01.clone();

    fromClone01.getName();

  }

}

 

 

 

 

 

适配器模式

比如,在一个画图的小程序中,你已经实现了绘制点、直线、方块等图形的功能。而且为
了让客户程序在使用的时候不用去关心它们的不同,还使用了一个抽象类来规范这些图形的接
口。现在你要来实现圆的绘制,这时你发现在系统其他的地方(textcircle)已经有了绘制圆的实现。在你庆
幸之余,发现系统中已有的方法和你在抽象类中规定的方法名称不一样!这可怎么办?修改绘
制圆的方法名,就要去修改所有使用它的地方;修改你的抽象类的方法名,也要去修改所有图形的实现方法以及已有的引用。还有其它的方法没有?那就是适配器模式了。可以看出使用适配器模式是为了在面向接口编程中更好的复用。

class Circle extends Shape
{
//这里引用了 TextCircle
private TextCircle tc;
public Circle ()
{
tc= new TextCircle(); //初始化
}
void public display()

{
tc.displayIt(); //在规定的方法里面调用 TextCircle 原来的方法
}
}

然后我们就能用

Circle mycircle = new circle();

Circle.display();

代理模式

说白了就是,在一些情况下客户不想或者不能直接引用一个对象,而代理对象可以在客户和目标对象之间起到中介作用,去掉客户不能看到的内容和服务或者增添客户需要的额外服务。

其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法

根据上文的阐述,代理模式就比较容易的理解了,我们看下代码:

[java] view plaincopy

1.  public interface Sourceable {  

2.      public void method();  

3.  }  

[java] view plaincopy

1.  public class Source implements Sourceable {  

2.    

3.      @Override  

4.      public void method() {  

5.          System.out.println("the original method!");  

6.      }  

7.  }  

[java] view plaincopy

1.  public class Proxy implements Sourceable {  

2.    

3.      private Source source;  

4.      public Proxy(){  

5.          super();  

6.          this.source = new Source();  

7.      }  

8.      @Override  

9.      public void method() {  

10.         before();  

11.         source.method();  

12.         atfer();  

13.     }  

14.     private void atfer() {  

15.         System.out.println("after proxy!");  

16.     }  

17.     private void before() {  

18.         System.out.println("before proxy!");  

19.     }  

20. }  

测试类:

[java] view plaincopy

1.  public class ProxyTest {  

2.    

3.      public static void main(String[] args) {  

4.          Sourceable source = new Proxy();  

5.          source.method();  

6.      }  

7.    

8.  }  

输出:

before proxy!
the original method!
after proxy!

代理模式的应用场景:

如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:

1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。

2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。

使用代理模式,可以将功能划分的更加清晰,有助于后期维护!

 

代理模式和适配器模式的差别:

两者的主要区别在于代理模式应用的情况是不改变接口命名的,而且是对已有接口功能的一种控制;而适配器模式则强调接口转换。

 

外观模式

外观是一个能为子系统和客户提供简单接口的类。当正确的应用外观,客户不再直接和子系统中的类交互,而是与外观交互。外观承担与子系统中类交互的责任。实际上,外观是子系统与客户的接口,这样外观模式降低了子系统和客户的耦合度 。外观模式意图:为子系统中的一组接口提供一个一致的接口。这个接口定义了一个高层接口,这个接口使得这一子系统更加容易使用

我们先看下实现类:

[java] view plaincopy

1.  public class CPU {  

2.        

3.      public void startup(){  

4.          System.out.println("cpu startup!");  

5.      }  

6.        

7.      public void shutdown(){  

8.          System.out.println("cpu shutdown!");  

9.      }  

10. }  

[java] view plaincopy

1.  public class Memory {  

2.        

3.      public void startup(){  

4.          System.out.println("memory startup!");  

5.      }  

6.        

7.      public void shutdown(){  

8.          System.out.println("memory shutdown!");  

9.      }  

10. }  

[java] view plaincopy

1.  public class Disk {  

2.        

3.      public void startup(){  

4.          System.out.println("disk startup!");  

5.      }  

6.        

7.      public void shutdown(){  

8.          System.out.println("disk shutdown!");  

9.      }  

10. }  

[java] view plaincopy

1.  public class Computer {  

2.      private CPU cpu;  

3.      private Memory memory;  

4.      private Disk disk;  

5.        

6.      public Computer(){  

7.          cpu = new CPU();  

8.          memory = new Memory();  

9.          disk = new Disk();  

10.     }  

11.       

12.     public void startup(){  

13.         System.out.println("start the computer!");  

14.         cpu.startup();  

15.         memory.startup();  

16.         disk.startup();  

17.         System.out.println("start computer finished!");  

18.     }  

19.       

20.     public void shutdown(){  

21.         System.out.println("begin to close the computer!");  

22.         cpu.shutdown();  

23.         memory.shutdown();  

24.         disk.shutdown();  

25.         System.out.println("computer closed!");  

26.     }  

27. }  

User类如下:

[java] view plaincopy

1.  public class User {  

2.    

3.      public static void main(String[] args) {  

4.          Computer computer = new Computer();  

5.          computer.startup();  

6.          computer.shutdown();  

7.      }  

8.  }  

输出:

start the computer!
cpu startup!
memory startup!
disk startup!
start computer finished!
begin to close the computer!
cpu shutdown!
memory shutdown!
disk shutdown!
computer closed!

 

 

 桥接模式

    桥接模式的做法是把变化部分抽象出来,使变化部分与主类分离开来,从而将多个维度的变化彻底分离。最后,提供一个管理类来组合不同维度上的变化,通过这种组合来满足业务的需要

桥接模式的意图是:将抽象与抽象方法的实现相互分离来实现解耦,以便二者可以相互独立的变化

下面举个例子说明:

 

1.现在水果里有 苹果和橘子

2.人分为 男人和女人

3.人都可以吃水果,所以有 2*2 = 4 中情况

 

如果我们不用桥接模式,那么实现这么多情况就需要一个一个的去实现,也就是4类,那么我们使用桥接模式呢?答案是:2类。这在条件和实现比较多的情况下优势会更明显。

 

//以下接口代表面条是否添加辣椒(该接口代表了面条在辣味风格这个维度上的变化)

 

 public interface Peppery{

           String style();

  }

//实现类代表辣椒的风格

public class PepperyStyle implements Peppery{

     public String style(){

          return "辣味";

     }

}

public class PlainStyle implements Peppery{

     public String style(){

          return "清淡" ;

     }

}

 

/^

 

对于系统而言,辣味风格这个维度上的变化是固定的,程序必须面对的,程序使用桥接模式将辣味风格这个维度的变化分离出来了,避免与牛肉、猪肉材料风格这个维度的变化耦合在一起。  

 

接下来是AbstractNoodle抽象类,其本身可以包含很多实现类,不同实现类则代表了面条在材料风格这个维度上的变化。

 

*/

 

public abstract class AbstractNoodle{

     protected Peppery style;

     public AbstractNoodle(Peppery style){

          this.style = style;  

     }

     public abstract void eat();

}

 

//这样就可以完成辣味风格、材料风格两个维度上变化的组合

/*

AbstractNoodle抽象类可看做是一个桥梁,它被用来“桥接”面条的材料风格的改变与辣味风格的改变,使面条的特殊属性得到无绑定的扩充。

 

*/

//以下是猪肉面实现类

public class PorkNoodle extends AbstractNoodle{

    public PorkyNodle(Peppery style){

         super(style);

    }

     public void eat(){

           System.out.println( "猪肉面条的口味:"+super.style.style());

     }

}

//测试类

public class Test{

     public static void main(String[] args){

         AbstractNoodle noodle = new PorkNoodle(new PepperyStyle());

         noodle.eat();

         AbstractNoodle noodle = new PorkNoodle(new PlainStyle());

         noodle.eat();

     }

}

 

策略模式

策略模式是对算法的封装它把算法的责任和算法本身分割开委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类

策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中退休的方便,策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定。这在一定程度上提高了系统的灵活性,但是客户端需要理解所有具体策略类之间的区别,以便选择合适的算法,这也是策略模式的缺点之一,在一定程度上增加了客户端的使用难度

 

责任链(Chain of Responsibility)模式 :责任链模式是对象的行为模式。使多个对象都有机会处理请求,从而避免请求的发送者和接受者直接的耦合关系。将这些对象连成一条链,沿着这条链传递该请求,直到有一个对象处理它为止

那么我们再模拟一下OA系统中请假审批流程,假如员工直接上司为小组长,小组长直接上司项目经理,项目经理直接上司部门经理,部门经理直接上司总经理。公司规定请假审批如下:

请假时间为t,时间单位day,简写d

t<  0.5d,小组长审批;

t>=0.5d,t<2,项目经理审批;

t>=2,t<5部门经理审批;

t>=5总经理审批;

 

可以看出肯定需要if  else。

责任链模式的优点是调用者不需知道具体谁来处理请求,也不知道链的具体结构,降低了节点域节点的耦合度;每个角色处理自己能处理的请求,不能处理则(交给)访问它的下家

 

 

观察者模式

观察者模式很好理解,类似于邮件订阅和RSS订阅,当我们浏览一些博客或wiki时,经常会看到RSS图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系

一个Observer接口:

[java] view plaincopy

1.  public interface Observer {  

2.      public void update();  

3.  }  

两个实现类:

[java] view plaincopy

1.  public class Observer1 implements Observer {  

2.    

3.      @Override  

4.      public void update() {  

5.          System.out.println("observer1 has received!");  

6.      }  

7.  }  

[java] view plaincopy

1.  public class Observer2 implements Observer {  

2.    

3.      @Override  

4.      public void update() {  

5.          System.out.println("observer2 has received!");  

6.      }  

7.    

8.  }  

Subject接口及实现类:

[java] view plaincopy

1.  public interface Subject {  

2.        

3.      /*增加观察者*/  

4.      public void add(Observer observer);  

5.        

6.      /*删除观察者*/  

7.      public void del(Observer observer);  

8.        

9.      /*通知所有的观察者*/  

10.     public void notifyObservers();  

11.       

12.     /*自身的操作*/  

13.     public void operation();  

14. }  

[java] view plaincopy

1.  public abstract class AbstractSubject implements Subject {  

2.    

3.      private Vector<Observer> vector = new Vector<Observer>();  

4.      @Override  

5.      public void add(Observer observer) {  

6.          vector.add(observer);  

7.      }  

8.    

9.      @Override  

10.     public void del(Observer observer) {  

11.         vector.remove(observer);  

12.     }  

13.   

14.     @Override  

15.     public void notifyObservers() {  

16.         Enumeration<Observer> enumo = vector.elements();  

17.         while(enumo.hasMoreElements()){  

18.             enumo.nextElement().update();  

19.         }  

20.     }  

21. }  

[java] view plaincopy

1.  public class MySubject extends AbstractSubject {  

2.    

3.      @Override  

4.      public void operation() {  //操作分两步

5.          System.out.println("update self!");   //1.自己更新

6.          notifyObservers();  //2 通知所有观察者

7.      }  

8.    

9.  }  


测试类:

[java] view plaincopy

1.  public class ObserverTest {  

2.    

3.      public static void main(String[] args) {  

4.          Subject sub = new MySubject();  

5.          sub.add(new Observer1());  

6.          sub.add(new Observer2());  

7.            

8.          sub.operation();  

9.      }  

10.   

11. }  

输出:

update self!
observer1 has received!
observer2 has received!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值