学习准备

1、23种设计模式学习

1> 适配器模式:类的适配、对象适配、接口适配

* 类的适配

source 待适配的类

public class Source {

 

public void method1(){

System.out.println("this is original method");

}

}

 

Targeter 适配后的类

public interface Targeter {

 

public void method1();

public void method2();

}

 

Adapter适配器

public class Adapter extends Source implements Targeter{

 

@Override

public void method2() {

System.out.println("this is targetable method!");

}

 

}

Test 测试类

public class Test {

 

public static void main(String[] args) {

Targeter t = new Adapter();

t.method1();

t.method2();

}

}

 

* 对象的适配

适配器

public class Adapter implements Targeter{

 

public Source source;

 

public Adapter(Source source) {

this.source = source;

}

 

@Override

public void method2() {

System.out.println("this is targetable method!");

}

 

@Override

public void method1() {

source.method1();

 

}

 

}

 

测试类

public class Test {

 

public static void main(String[] args) {

Source s = new Source();

Targeter t = new Adapter(s);

t.method1();

t.method2();

}

}

 

 

*接口的适配

主要是为了解决这类问题:一个接口有好多方法,有的类用不到这么多,如果实现该接口就要实现所有的方法,代码多,这种情况可以考虑接口的适配,用一个抽象类实现该接口,之后的类继承该抽象类,不与接口直接打交道

抽象类:

public abstract class Wrapper implements Targeter{

 

@Override

public void method1() {}

@Override

public void method2() {

}

}

 

具体类

public class SourceSub extends Wrapper{

 

@Override

public void method1() {

System.out.println("this is method1");

}

}

 

public class SourceSub2 extends Wrapper{

 

@Override

public void method2() {

System.out.println("this is method2");

}

}

 

测试类

public class Test {

 

public static void main(String[] args) {

Wrapper w1 = new SourceSub();

Wrapper w2 = new SourceSub2();

w1.method1();

w2.method2();

}

}

 

2> 装饰模式

适合:能用到某个方法,但这个方法不完整,可以用装饰模式来修饰这个方法

被装饰类compennent

 

public interface Compon {

 

public void method();

}

 

public class Component implements Compon{

 

@Override

public void method(){

System.out.println("this is original method");

}

}

 

装饰类

public class Decorator implements Compon{

 

public Component c;

 

public Decorator(Component c) {

this.c = c;

}

 

@Override

public void method(){

System.out.println("before decorator");

c.method();

System.out.println("after decorator");

}

}

 

测试类

public class Test {

 

public static void main(String[] args) {

Component c =new Component();

Decorator d = new Decorator(c);

c.method();

d.method();

}

}

 装饰模式的应用场景:
        ①需要扩展一个类的功能
        ②动态的为一个对象增加功能,而且还能动态撤销(继承做不到这一点,
继承的功能都是静态的,不能动态删减)
        ③缺点:产生太多相似的对象,不易排错
 
3> 单例模式
单例模式有几种实现

public class Singleton {

 

private static Singleton instance = null;

 

private Singleton() {

}

 

public static Singleton getInstance(){

if(instance == null){

instance = new Singleton();

}

return instance;

}

}

缺点:在多线程环境下,不安全

 

 

public class Singleton2 {

 

private static Singleton2 instance = null;

 

private Singleton2() {

}

 

public static synchronized Singleton2 getInstance() {

if (instance == null) {

instance = new Singleton2();

}

return instance;

}

}

 

缺点:效率不高,每次调用该方法都要对该对象加锁

 

private static Singleton3 instance = null;

 

private Singleton3() {

}

 

public static Singleton3 getInstance(){

if(instance == null){

synchronized(instance){

if(instance == null){

instance = new Singleton3();

}

}

}

return instance;

}

}

缺点:

将synchronized关键字加在了内部,也就是说当调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升。但是,这样的情况,还是有可能有问题的,看下面的情况:在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,我们以A、B两个线程为例:

a>A、B线程同时进入了第一个if判断

b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();

c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。

d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。

e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。

*比较完美

public class Singleton4 {

 

private Singleton4() {

}

 

private static class SingletonFactory{

private static Singleton4 instance = new Singleton4();

}

 

public static Singleton4 getInstance(){

return SingletonFactory.instance;

}

}

单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。

 

4>工厂方法模式

普通工厂模式、多工厂模式、静态工厂模式 较简单,但违反开闭原则,即对扩展开放,对修改关闭,因为如果要扩展的话必须修改代码

 

5>抽象工厂模式

把工厂抽象,这样扩展的话,只要再实现抽象工厂增加类就可以,符合开闭原则

 

6>建造者模式

工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性。

[java] view plain copy
  1. public interface Sender {  
  2.     public void Send();  
  3. }  

两个实现类:

[java] view plain copy
 
  1. public class MailSender implements Sender {  
  2.     @Override  
  3.     public void Send() {  
  4.         System.out.println("this is mailsender!");  
  5.     }  
  6. }  
[java] view plain copy
 
  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 Builder {  
  2.       
  3.     private List<Sender> list = new ArrayList<Sender>();  
  4.       
  5.     public void produceMailSender(int count){  
  6.         for(int i=0; i<count; i++){  
  7.             list.add(new MailSender());  
  8.         }  
  9.     }  
  10.       
  11.     public void produceSmsSender(int count){  
  12.         for(int i=0; i<count; i++){  
  13.             list.add(new SmsSender());  
  14.         }  
  15.     }  
  16. }  

测试类

  1. public class Test {  
  2.   
  3.     public static void main(String[] args) {  
  4.         Builder builder = new Builder();  
  5.         builder.produceMailSender(10);  
  6.     }
  7. }

7>原型模式

public class Prototype implements Cloneable , Serializable{

 

private static final long serialVersionUID = 6575573039264223590L;

 

private int i;

private Person p;

 

//浅复制

@Override

public Object clone() throws CloneNotSupportedException {

Prototype prototype = (Prototype) super.clone();

return prototype;

}

 

//深复制

public Object deepClone() throws CloneNotSupportedException, IOException, ClassNotFoundException {

ByteArrayOutputStream bao = new ByteArrayOutputStream();

ObjectOutputStream oo = new ObjectOutputStream(bao);

oo.writeObject(this);

 

ByteArrayInputStream bai = new ByteArrayInputStream(bao.toByteArray());

ObjectInputStream ois = new ObjectInputStream(bai);

Object object = ois.readObject();

 

return object;

}

 

 

@Override

public String toString() {

return "Prototype [i=" + i + ", p=" + p + "]";

}

 

public int getI() {

return i;

}

 

public void setI(int i) {

this.i = i;

}

 

public Person getP() {

return p;

}

 

public void setP(Person p) {

this.p = p;

}

 

}

一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的。首先需要了解对象深、浅复制的概念:

浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。

深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。

原文地址:https://www.cnblogs.com/-wyl/p/7156687.html