第8篇-JAVA面向对象-设计模式Ⅳ

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第8篇-JAVA面向对象-设计模式Ⅳ相关的知识,希望对你有一定的参考价值。

第8篇-JAVA面向对象-设计模式Ⅳ

  • 每篇一句 : 想象是程序的创作之源

  • 初学心得 : 平静的海洋练不出熟练的水手

  • (笔者:JEEP/711)[JAVA笔记 | 时间:2017-04-11| JAVA面向对象 Ⅳ]

JAVA设计模式

什么是JAVA设计模式以及作用? 
设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结 
使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性,本篇将介绍10种JAVA常用设计模式

1.JAVA 设计模式 - 单例设计模式

单例模式是一种创建模式,这种模式只涉及一个单独的类,它负责创建自己的对象 
该类确保只创建单个对象,这个类提供了一种访问其唯一对象的方法 
单例模式目的是为了整个应用中有且只有一个实例,所有指向该类型实例的引用都指向这个实例 
保证对象不能再类的外部被随意实例化,解决方法:将构造器进行私有化处理 
保证类创建的过程发生在类的内部,还有保证在类的外部能拿到在类的内部初始化的对象

单例模式类型:饿汉式单例,懒汉式单例

Singleton(饿汉模式) 
饿汉模式,特点是程序加载类的时候比较慢,但运行时获得对象的速度比较快,它从加载到应用结束会一直占用资源 
饿汉模式代码:

1.class Singleton {
2.       public class SingletonDemo {
3.  public static void main(String[] args) {
4.      Singleton1 s1 = Singleton1.getInstance();
5.      Singleton1 s2 = Singleton1.getInstance();
6.      System.out.println(s1==s2);  //true
7.      Singleton2 s3 = Singleton2.getInstance();
8.      Singleton2 s4 = Singleton2.getInstance();
9.      System.out.println(s3==s4);  //true
10.  }
11.}
12.class Singleton1{
13.  private static final Singleton1 instance = new Singleton1();  //在内部准备好一个对象  
14.  public static Singleton1 getInstance(){
15.      return instance;
16.  }
17.  private Singleton1(){}
18.  public void show(){
19.      System.out.println("Singleton1");
20.  }
21.}
22.class Singleton2 {
23.  private static Singleton2 instance;
24.  //将instance传递到外部去
25.  public static Singleton2 getInstance(){ 
26.      if(instance == null){
27.          instance = new Singleton2();
28.      }
29.      return instance;
30.  }
31.  private Singleton2(){}
32.}

Singleton(懒汉模式) 
懒汉模式特点,程序是运行时获得对象的速度比较慢,但加载类的时候比较快 
它在整个应用的生命周期只有一部分时间在占用资源 
懒汉模式代码:

1.class Singleton{
2.  private static Singleton instance = null;
3.  public static Singleton getInstance(){// 将instance传递到外部去
4.      if(instance == null){
5.          instance = new Singleton();
6.      }
7.      return instance;
8.  }
9.  private Singleton(){}
10.}
11.public static Singleton2 getInstance(){
12.     if(instance == null){
13.        synchronized(Singleton2.class){
14.             if(instance == null){
15.                instance = new Singleton2(); 
16.              }
17.          }
18.     }     
19.   return instance;
20.  }

Singleton(饿汉模式) & Singleton(懒汉模式) 区别 
(1)这两种模式对于初始化较快,占用资源少的轻量级对象来说,没有多大的性能差异,选择懒汉式或饿汉式都没有问题
但是对于初始化慢,占用资源多的重 量级对象来说,就会有比较明显的差别了 
所以,对重量级对象应用饿汉模式,类加载时速度慢,但运行时速度快;懒汉模式则与之相反,类加载时速度快,但运行时第一次获得对象的速度慢 
(2)从用户体验的角度来说,我们应该首选饿汉模式。我们愿意等待某个程序花较长的时间初始化,却不喜欢在程序运行时等待太久,给人一种反应迟钝的感觉,所以对于有重量级对象参与的单例模式,笔者推荐使用饿汉模式

2.JAVA设计模式 - 享元设计模式

在JAVA语言中,String类型就是使用了享元模式。String对象是final类型,对象一旦创建就不可改变 
在JAVA中字符串常量都是存在常量池中的,JAVA会确保一个字符串常量在常量池中只有一个拷贝 
String a=”abc”,其中”abc”就是一个字符串常量 
享元模式代码:

1.public class Test {
2.   public static void main(String[] args) {
3.       String a = "abc";
4.       String b = "abc";
5.       System.out.println(a == b);
6.   }
7.}

上面的例子中结果为:true ,这就说明a和b两个引用都指向了常量池中的同一个字符串常量”abc” 
这样的设计避免了在创建N多相同对象时所产生的不必要的大量的资源消耗

3.JAVA设计模式 - 简单工厂设计模式

简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例 
简单工厂模式是工厂模式家族中最简单实用的模式,工厂模式就是用来生成对象的 
简单工厂设计模式作用:降低耦合

简单工厂模式代码:

1.//手机标准
2.interface ICellPhone {
3.  void sendMsg();
4.}
5./* 小米手机 */
6.class Millet implements ICellPhone {
7.  public void sendMsg() {
8.  }
9.}
10./* 华为手机 */
11.class Huawei implements ICellPhone {
12.  public void sendMsg() {
13.  }
14.}
15./* 手机工厂 */
16.class Factory {
17.  public static ICellPhone getInstance(String type){
18.      ICellPhone phone = null;
19.      if("millet".equalsIgnoreCase(type)){
20.          phone = new Millet();
21.      }else if("huawei".equalsIgnoreCase(type)){
22.          phone = new Huawei();
23.      }
24.      return phone;
25.  }
26.}
27.public class FactoryDemo {
28.  public static void main(String[] args) {
29.      ICellPhone p = Factory.getInstance("millet");
30.  }
31.}

如果直接使用了被调用者对象,而且又有可能会变化,那这个代码的可扩展性和柔韧性就不是很强基于这样的问题,所有我们就提出把客户端(调用者)不直接跟要调用的对象产生依赖关系,这样在扩展性和柔韧性会好一些,加入中间人,来引入工厂模式调控,单独声明一个工厂类,属于被调用者这一边,简单工厂类只负责产生对象

4.JAVA设计模式 - 抽象工厂设计模式

抽象工厂模式与简单工厂模式的区别: 
(1)抽象工厂模式是简单工厂方法模式的升级版本,它用来创建一组相关或者相互依赖的对象。它与简单工厂方法模式的区别就在于,简单工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构 
(2)在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,简单工厂方法模式提供的所有产品都是衍生自同一个2接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类 
(3)在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构

抽象工厂模式代码:

1.interface IProduct1 {
2.       public void show();
3.   }
4.   interface IProduct2 {
5.       public void show();
6.   }
7.   class Product1 implements IProduct1 {
8.       public void show() {
9.           System.out.println("这是1型产品");
10.       }
11.   }
12.   class Product2 implements IProduct2 {
13.       public void show() {
14.           System.out.println("这是2型产品");
15.       }
16.   }
17.   interface IFactory {
18.       public IProduct1 createProduct1();
19.       public IProduct2 createProduct2();
20.   }
21.   class Factory implements IFactory{
22.       public IProduct1 createProduct1() {
23.           return new Product1();
24.       }
25.       public IProduct2 createProduct2() {
26.           return new Product2();
27.       }
28.   }
29.   public class Client {
30.       public static void main(String[] args){
31.           IFactory factory = new Factory();
32.           factory.createProduct1().show();
33.           factory.createProduct2().show();
34.       }
35.   }

抽象工厂模式的优点: 
抽象工厂模式除了具有简单工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束,所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理 
抽象工厂模式的缺点: 
产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改,所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的 
适用场景 
当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式,说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式,假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点

5.JAVA设计模式 - 装饰设计模式

装饰模式在不链接其结构的情况下向现有对象添加新功能,它是一种结构型模式,因为它充当现有类的包装器 
装饰模式创建一个装饰器类来包装原始类并提供其他功能 
装饰模式代码:

1.interface Printer {
2.  void print();
3.}
4.
5.class PaperPrinter implements Printer {
6.  @Override
7.  public void print() {
8.     System.out.println("Paper Printer");
9.   }
10.}
11.
12.class PlasticPrinter implements Printer {
13.  @Override
14.  public void print() {
15.     System.out.println("Plastic Printer");
16.   }
17.}
18.
19.abstract class PrinterDecorator implements Printer {
20.  protected Printer decoratedPrinter;
21.  public PrinterDecorator(Printer d){
22.     this.decoratedPrinter = d;
23.  }
24.  public void print(){
25.     decoratedPrinter.print();
26.   }  
27.}
28.
29.class Printer3D extends PrinterDecorator {
30.  public Printer3D(Printer decoratedShape) {
31.     super(decoratedShape);    
32.  }
33.  @Override
34.  public void print() {
35.    System.out.println("3D.");
36.    decoratedPrinter.print();         
37.   }
38.}
39.
40.public class Main {
41.  public static void main(String[] args) {
42.     Printer plasticPrinter = new PlasticPrinter();
43.     Printer plastic3DPrinter = new Printer3D(new PlasticPrinter());
44.     Printer paper3DPrinter = new Printer3D(new PaperPrinter());
45.     plasticPrinter.print();
46.     plastic3DPrinter.print();
47.     paper3DPrinter.print();
48.   }
49.}

6.JAVA设计模式 - 观察者设计模式

定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新 
观察者模式中,包括以下四个角色: 
(1)被观察者:类中有一个用来存放观察者对象的Vector容器(之所以使用Vector而不使用List,是因为多线程操作时,Vector在是安全的,而List则是不安全的),这个Vector容器是被观察者类的核心,另外还有三个方法:attach方法是向这个容器中添加观察者对象;detach方法是从容器中移除观察者对象;notify方法是依次调用观察者对象的对应方法。这个角色可以是接口,也可以是抽象类或者具体的类,因为很多情况下会与其他的模式混用,所以使用抽象类的情况比较多 
(2)观察者:观察者角色一般是一个接口,它只有一个update方法,在被观察者状态发生变化时,这个方法就会被触发调用 
(3)具体的被观察者:使用这个角色是为了便于扩展,可以在此角色中定义具体的业务逻辑 
(4)具体的观察者:观察者接口的具体实现,在这个角色中,将定义被观察者对象状态发生变化时所要处理的逻辑

观察者模式代码实现:

1.abstract class Subject {
2.       private Vector obs = new Vector();
3.       public void addObserver(Observer obs){
4.           this.obs.add(obs);
5.       }
6.       public void delObserver(Observer obs){
7.           this.obs.remove(obs);
8.       }
9.       protected void notifyObserver(){
10.          for(Observer o: obs){
11.               o.update();
12.           }
13.       }
14.       public abstract void doSomething();
15.   }
16.   class ConcreteSubject extends Subject {
17.       public void doSomething(){
18.           System.out.println("被观察者事件");
19.           this.notifyObserver();
20.       }
21.   }
22.   interface Observer {
23.       public void update();
24.   }
25.   class ConcreteObserver1 implements Observer {
26.       public void update() {
27.           System.out.println("观察者1收到信息进行处理");
28.       }
29.   }
30.   class ConcreteObserver2 implements Observer {
31.       public void update() {
32.           System.out.println("观察者2收到信息进行处理");
33.       }
34.   }
35.   public class Client {
36.       public static void main(String[] args){
37.           Subject sub = new ConcreteSubject();
38.           sub.addObserver(new ConcreteObserver1());  //添加观察者1
39.           sub.addObserver(new ConcreteObserver2());  //添加观察者2
40.           sub.doSomething();
41.       }
42.   }

观察者模式的优点:观察者与被观察者之间是属于轻度的关联关系,并且是抽象耦合的,这样对于两者来说都比较容易进行扩展,观察者模式是一种常用的触发机制,它形成一条触发链,依次对各个观察者的方法进行处理,但同时,这也算是观察者模式一个缺点,由于是链式触发,当观察者比较多的时候,性能问题是比较令人担忧的。并且,在链式结构中,比较容易出现循环引用的错误,造成系统假死

7.JAVA设计模式 - 适配器设计模式

在JAVA设计模式中,适配器模式作为两个不兼容接口之间的桥梁 
通过使用适配器模式,可以统一两个不兼容的接口 
适配器设计模式代码:

1.//适配器模式
2.public class Shipeiqi{
3.  public static void main(String [] args){
4.      ModificationWindow i = new ModificationWindow();
5.      i.close();  
6.   }
7.}
8.
9.//定义一个接口
10.interface IWindow{
11.  void man();//只声明方法,
12.  void min();//只声明方法
13.   void close();//只声明方法,
14.}
15.
16.//定义一个抽象实现
17.abstract class MyWindow implements IWindow{
18.  public void man(){};
19.  public void min(){};
20.  public void close(){};
21.}
22.
23.//定义一个类继承接口
24.class ModificationWindow extends MyWindow{
25.  public void close(){
26.      System.out.println("我将实现关闭功能");
27.   }
28.}

8.JAVA设计模式 - 静态代理设计模式

静态代理设计模式:如生活当中的代理,代驾,代购,待产… 
代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问 
代理模式,白了就是“真实对象”的代表,在访问对象时引入一定程度的间接性,因为这种间接性可能附和多种用途(权限的控制、对象的访问、远程的代理) 
代理类第一先要实现接口,第二要维护一个代理的对象,代理对象也是通过主题接口声明的,再通过构造方法或者get,set传值,这就是静态代理

静态代理模式代码:

1.//静态代理设计模式
2.
3.//声明一个类
4.public class Jingtai{
5.  //主方法
6.  public static void main(String [] args){
7.      Person p = new Person("老王 ");//实例化Person对象
8.      //创建代理对象,并把被代理对象传进来,p传给了Matchmaker类中的target
9.      Matchmaker m = new Matchmaker(p); //需要一个代理对象,把被代理对象传过来
10.      m.miai();//真正执行调用的是     
11.   }
12.}
13.
14.//定义一个接口  主题接口
15.interface Subject{
16.  public void miai();//抽象方法
17.}
18.
19.//代理相当于代理接口的方法
20.//定义实现一个接口,相当于被代理类
21.class Person implements Subject{
22.  private String name;//定义私有的属性
23.  //一参构造方法
24.  public Person(String name){
25.      this.name = name;
26.  }
27.
28.  //定义实现方法
29.  public void miai(){
30.      System.out.println(name+"正在相亲中...");//输出
31.   }
32.}
33.
34.//定义一个代理类,代理的是过程,实现以后,是为了实现方法,需要重写方法
35.class Matchmaker implements Subject{
36.  private Subject target;//要代理的目标对象,通过定义一个代理的对象实现的接口,代理一个对象或者说一个属性,
37.  //可以用构造方法传值,也可以用get,set方法传值
38.  //构造方法传值
39.  public Matchmaker(Subject target){
40.      this.target = target;
41.  }
42.
43.  //相亲之前要做的事情,封装起来
44.  private void before(){
45.      System.out.println("为代理人,匹配如意郎君");
46.  }
47.
48.  //相亲之后要做的事情
49.  private void after(){
50.      System.out.println("本次相亲结束.");  
51.  }
52.
53.  //需要重写方法,相亲的方法
54.  public void miai(){
55.      before();//调用相亲之前要做的事情
56.      target.miai();//真正执行相亲的方法,调用需要目标对象
57.      after();//相亲之后要做的事情
58.  }
59.}

9.JAVA设计模式 - 迭代器设计模式

迭代器模式以顺序方式访问集合对象的元素 
迭代器模式代码:

1.interface Iterator {
2.  public boolean hasNext();
3.  public Object next();
4.}
5.class LetterBag {
6.  public String names[] = {"R" , "J" ,"A" , "L"};
7.  public Iterator getIterator() {
8.     return new NameIterator();
9.  }
10.  class NameIterator implements Iterator {
11.     int index;
12.     @Override
13.     public boolean hasNext() {
14.        if(index < names.length){
15.           return true;
16.        }
17.        return false;
18.     }
19.     @Override
20.     public Object next() {
21.        if(this.hasNext()){
22.           return names[index++];
23.        }
24.        return null;
25.     }    
26.  }
27.}
28.public class Main {
29.  public static void main(String[] args) {
30.     LetterBag bag = new LetterBag();
31.     for(Iterator iter = bag.getIterator(); iter.hasNext();){
32.        String name = (String)iter.next();
33.        System.out.println("Name : " + name);
34.     }   
35.  }
36.}

迭代器模式的优点: 
简化了遍历方式,对于对象集合的遍历,还是比较麻烦的,对于数组或者有序列表,可以通过下坐标来取得,但用户需要在对集合了解很清楚的前提下,自行遍历对象,但是对于hash表来说,用户遍历起来就比较麻烦了,而引入了迭代器方法后,用户用起来就简单的多了,可以提供多种遍历方式,比如说对有序列表,我们可以根据需要提供正序遍历,倒序遍历两种迭代器,用户用起来只需要得到我们实现好的迭代器,就可以方便的对集合进行遍历了,封装性良好,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用去关心 
迭代器模式的缺点: 
对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐,像ArrayList,宁可愿意使用for循环和get方法来遍历集合

10.JAVA设计模式 - 生产者与消费者设计模式

生产者与消费者模式代码:

1.package cn.sc;
2./**
3.*生产者与消费者应用案例
4.*sleep与wait区别
5.*sleep让当前的线程进入休眠状态,让出cpu,让其他线程执行
6.*如果用同步的话,有对象锁的时候,是不会释放的,只能等待此线程使用完,才可以使用
7.*wait会释放对象锁,必须等待其他线程唤醒
8.*@author JEEP-711
9.*
10.*/
11.public class ScXf {
12.  public static void main(String[] args) {
13.      Phones p = new Phones(null, null);//创建Phones对象
14.      PhoneSc s = new PhoneSc(p);//创建PhoneSc对象 
15.      PhoneXf x = new PhoneXf(p);//创建PhoneXf对象
16.      new Thread(s).start();//启动生产者线程
17.      new Thread(x).start();//启动消费者线程
18.   }
19.}
20.
21./**
22.* 手机生产者,单独的生产者,实现Runnable接口
23.* @author JEEP-711
24.*
25.*/
26.class PhoneSc implements Runnable{
27.  private Phones phones;
28.  public PhoneSc(Phones phones){
29.      this.phones = phones;
30.  }
31.  @Override
32.  public void run() {
33.      //不断地生产20份,生产的过程
34.      for (int i = 0; i < 50; i++) {
35.          if(i%2==0){
36.              phones.set("金立手机", "金立手机,中国造!");
37.          }else{
38.              phones.set("小米手机", "小米手机,为发烧而生!");
39.          }
40.      }
41.   }
42.}
43.
44./**
45. *手机消费者,顾客
46.*@author JEEP-711
47.*
48.*/
49.class PhoneXf implements Runnable{
50.  private Phones phones;
51.  public PhoneXf(Phones phones){
52.      this.phones = phones;
53.  }
54.  @Override
55.  public void run() {
56.      for (int i = 0; i < 50; i++) {
57.          phones.get();//调用消费产品方法
58.      }
59.   }  
60.}
61.
62./**
63.*产品的对象,生产的手机
64.*@author JEEP-711
65.*
66.*/
67.class Phones{
68.  @Override
69.  public String toString() {
70.      return "Phones [name=" + name + ", content=" + content + "]";
71.  }
72.  private String name;
73.  private String content;
74.  /**true表示可以生产,false表示可以消费
75.*作为标记,如何flag等于true表示可以生产,如何flag等于false表示不可生产
76.*如果flag等于false表示可以消费状态,可以取走,flag等于true表示不能取走
77.*解决重复值得问题
78.*/
79.  private boolean flag = true;//表示可以生产,false表示可以消费
80.  //构造方法
81.  public Phones(String name, String content) {
82.      super();
83.      this.name = name;
84.      this.content = content;
85.  }
86.  //取得名称方法
87.  public String getName() {
88.      return name;
89.  }
90.  //设置名称方法
91.  public void setName(String name) {
92.      this.name = name;
93.  }
94.  //取得内容方法
95.  public String getContent() {
96.      return content;
97.  }
98.  //设置内容方法
99.  public void setContent(String content) {
100.      this.content = content;
101.  }   
102.
103.  /**
104.   *通过同步,解决了取值错误问题
105.   *@param name
106.   *@param content
107.   */
108.  //生产制造同步方法
109.  public synchronized void set(String name, String content){
110.      if(!flag){
111.          try {
112.          //调用该方法,当前线程进入等待池等待状态,没有指定时间,
113.          //需要其他线程唤醒,释放对象锁,让出cpu
114.              this.wait();
115.          } catch (InterruptedException e) {
116.              e.printStackTrace();
117.          }
118.      }
119.      this.setName(name);
120.      try {
121.          Thread.sleep(300);
122.      } catch (InterruptedException e) {
123.          e.printStackTrace();
124.      }
125.      this.setContent(content);
126.      flag = false;//表示可以消费,取走
127.      this.notify();//唤醒在该监视器上的一个线程
128.  }   
129.
130.  //消费产品同步取值方法
131.  public synchronized void get(){
132.      if(flag){
133.          try {
134.              //调用该方法,当前线程进入等待池等待状态,没有指定时间,
135.              //需要其他线程唤醒,释放对象锁,让出cpu
136.              this.wait();
137.          } catch (InterruptedException e) {
138.              e.printStackTrace();
139.          }
140.      }
141.      try {
142.          Thread.sleep(300);
143.      } catch (InterruptedException e) {
144.          e.printStackTrace();
145.      }
146.      System.out.println(this.getName()+":"+this.getContent());
147.      flag = true;
148.      this.notify();
149.   }  
150.}

初学(面向对象近阶段) Ⅳ 难点: ★★★★★★★

希望每一篇文章都能够对读者们提供帮助与提升,这乃是每一位笔者的初衷


感谢您的阅读 欢迎您的留言与建议


本文出自 “JEEP711” 博客,请务必保留此出处http://jeep711.blog.51cto.com/12970787/1934211

以上是关于第8篇-JAVA面向对象-设计模式Ⅳ的主要内容,如果未能解决你的问题,请参考以下文章

第5篇-JAVA面向对象Ⅰ

Java初学者推荐学习书籍PDF免费下载

面向对象程序设计(JAVA) 第8周学习指导及要求

2017面向对象程序设计(Java) 第1周学习指导及要求(2017.8.24-2017.8.27)

201771010120 苏浪浪 面向对象程序设计(Java)第10周

第6篇-JAVA面向对象Ⅱ