1

设计模式

此文章部分来于网络,为了学习总结。

一、原型模式(Prototype)

介绍:从一个对象再创建另一个对象,而不需知道任何细节。

1、两种表现形式

(1)简单形式
原型模式(简单形式)

(2)登记形式
原型模式(登记形式)

这两种表现形式仅仅是原型模式的不同实现。

2、俩种克隆方法

(1)浅复制

介绍:只克隆值传递的数据(比如基本数据类型、String),而不复制它所引用的对象,就是对其他对象的引用都指向原来的对象。

注意:可实现Cloneable接口。

(2)深复制

介绍:除了浅度克隆要克隆的值外,还负责克隆引用类型的数据,把要复制的对象所引用的对象都复制了一遍。

注意:采用字节流写入写出对象,所有对象必须实现Serializable。Thread和Socket对象必须设置transient,不予复制。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Prototype implements Cloneable, Serializable{
    
    @Override
    protected Object clone() throws CloneNotSupportedException { //浅克隆
        // TODO Auto-generated method stub
        Prototype prototype = (Prototype) super.clone();
        return prototype;
    }
    
    public Object deepClone(){ //深克隆
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return ois.readObject();
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            return null;
        }
    }
    
}

二、模板方法模式

介绍:将重复的部分上升到父类。

举例:公司的面试题是相同的,只有应聘者的答案不同,所以相同的问题在父类中表现,子类只用作记录答案。

public class TestPaper {
    
    public void testQuestion1(){
        System.out.println("1 + 1 = ");
        System.out.println("答案是:" + answer());
    }
    
    protected String answer(){
        return "";
    }

}
public class TestPaperA extends TestPaper {
    
    @Override
    protected String answer() {
        // TODO Auto-generated method stub
        return "2";
    }

}
public class Client {
    
    public static void main(String[] args) {
        TestPaper testPagerA = new TestPaperA();
        testPagerA.question();        
    }
    
}

三、外观模式(Fade)

介绍:定义一个高层接口,使得子系统更容易使用。

外观模式

四、建造者模式(Builder)

介绍:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

图片描述

举例:遇到多个构造器参数时考虑使用构建器,而不是重叠构造器模式或JavaBean模式调用setter方法。(静态工厂和构造器有个共同的局限性:它们不能很好地扩展大量的可选参数)

/**
 * 构建器模式
 * @author alex
 * @date 2017年4月6日
 */
public class A {
    
    private final int a;
    private final int b;
    private final int c;
    
    public static class A_son {
        private final int a;
        private final int b;
        private int c = 0;
        
        public A_son(int a, int b) {
            this.a = a;
            this.b = b;
        }

        public A_son c(int val) { 
            c = val;
            return this;
        }
        
        public A build() {
            return new A(this);
        }
        
    }

    public A(A_son a_son) {
        a = a_son.a;
        b = a_son.b;
        c = a_son.c;
    }
    
}
A a = new A.A_son(12, 12).c(12).build(); //客户端调用

缺点:构建器模式可能比重叠构造器更加冗长,参数多时使用较好。如果构建器没有在最初使用,后期使用会有些难以控制,通常一开始就使用构建器。

优点:构建器比重叠构造器的客户端代码易读写。比JavaBean更安全。

五、观察者模式

六、工厂方法模式

图片描述

举例:项目中可能需要访问多种类型的数据库,数据库访问与逻辑业务应该独立分开,只需在客户端创建工厂类。

七、抽象工厂模式

图片描述

八、状态模式

介绍:将对象转换的逻辑判断转移到不同状态的类中,来简化复杂的逻辑判断。如果逻辑判断很简单就不需要用此模式了。

图片描述

abstract class State {
    
    public abstract void handle(Context context);

}

public class Context {
    
    private State state;

    public Context(State state) {
        this.state = state;
    }
    
    public void request() {
        state.handle(this);
    }

    public State getState() {
        System.out.println("当前状态: " + state.getClass().toString());
        return state;
    }

    public void setState(State state) {
        this.state = state;
        getState();
    }
    
}

public class ConcreteStateA extends State {

    @Override
    public void handle(Context context) {
        // TODO Auto-generated method stub
        context.setState(new ConcreteStateB()); // 创建下一个逻辑判断
    }

}
public class ConcreteStateB extends State {

    @Override
    public void handle(Context context) {
        // TODO Auto-generated method stub
        context.setState(new ConcreteStateA());
    }

}

public class Test {
    
    public static void main(String[] args) {
        Context context = new Context(new ConcreteStateA());
        context.request();
        context.request();
        context.request();
    }

}

九、适配器模式

介绍:系统的数据和行为都正确,但接口不符时,使得一个原有对象与某个接口匹配。

举例:假如巴西队中有中国球员,防止语言间的差异,中国球员需要翻译来与团队交流。

图片描述

十、备忘录模式

介绍:捕获一个对象的内部状态,并在该对象之外保存这个状态。之后可恢复之前的状态。

public class Originator {
    
    private String state;
    
    public Memento createMemento() {
        return new Memento(state);
    }
    
    public void setMemento(Memento memento) {
        state = memento.getState();
    }
    
    public void show() {
        System.out.println("state =" + state);
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
    
}

public class Caretaker {
    
    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }
    
}

public class Memento {
    
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
    
}

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Originator originator = new Originator();
        originator.setState("on");
        originator.show();
        
        Caretaker caretaker = new Caretaker();
        caretaker.setMemento(originator.createMemento());
        
        originator.setState("asdasd");
        originator.show();
        
        originator.setMemento(caretaker.getMemento());
        originator.show();
    }

}

缺点:易消耗内存。

十一、组合模式

介绍:将对象组合成树形结构来表示部分-整体,使部分与整体具有一致性。

public abstract class Component {

    protected String name;

    public Component(String name) {
        this.name = name;
    }
    
    public abstract void add(Component c);
    public abstract void remove(Component c);
    public abstract void display(int depth);
    
}

import org.apache.commons.lang.StringUtils;

public class Leaf extends Component {

    public Leaf(String name) {
        super(name);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void add(Component c) {
        // TODO Auto-generated method stub
        System.out.println("Don't add component");
    }

    @Override
    public void remove(Component c) {
        // TODO Auto-generated method stub
        System.out.println("Don't remove component");
    }

    @Override
    public void display(int depth) {
        // TODO Auto-generated method stub
        System.out.println(StringUtils.repeat("-", depth) + name);
    }

}

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;

public class Composite extends Component {
    
    private List<Component> list = new ArrayList<Component>();

    public Composite(String name) {
        super(name);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void add(Component c) {
        // TODO Auto-generated method stub
        list.add(c);
    }

    @Override
    public void remove(Component c) {
        // TODO Auto-generated method stub
        list.remove(c);
    }

    @Override
    public void display(int depth) {
        // TODO Auto-generated method stub
        System.out.println(StringUtils.repeat("-", depth) + name);
        for (Component component : list) {
            component.display(depth + 2);
        }
    }

}

public class Test {
    
    public static void main(String[] args) {
        Composite root = new Composite("root");
        
        root.add(new Leaf("Leaf A"));
        root.add(new Leaf("Leaf B"));
        
        Composite comp = new Composite("Composite X");
        comp.add(new Leaf("Leaf XA"));
        comp.add(new Leaf("Leaf XB"));
        
        root.add(comp);
        
        Composite comp2 = new Composite("Composite Y");
        root .add(comp2);
        
        root.display(1);
    }

}

十二、迭代器模式

介绍:提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示

/**
 * 迭代器抽象
 * @author chenguyan
 * @date 2017年6月16日
 */
public abstract class Iterator {
    
    public abstract Object first();
    public abstract Object next();
    public abstract boolean isDone();
    public abstract Object currentItem();

}

/**
 * 聚集抽象
 * @author chenguyan
 * @date 2017年6月16日
 */
public abstract class Aggregate {

    public abstract Iterator createIterator();

}

/**
 * 具体聚集
 * @author chenguyan
 * @date 2017年6月16日
 */
public class ConcreteAggregate extends Aggregate {

    private List<Object> items = new ArrayList<Object>();
    
    @Override
    public Iterator createIterator() {
        // TODO Auto-generated method stub
        return new ConcreteIterator(this);
    }
    
    public int count() {
        return items.size();
    }
    
    public Object get(int index) {
        return items.get(index);
    }
    
    public void add(Object obj) {
        items.add(obj);
    }

}

/**
 * 具体迭代器
 * @author chenguyan
 * @date 2017年6月16日
 */
public class ConcreteIterator extends Iterator {
    
    private ConcreteAggregate concreteAggregate;
    private int current = 0;
    
    public ConcreteIterator(ConcreteAggregate concrete) {
        // TODO Auto-generated constructor stub
        this.concreteAggregate = concrete;
    }

    @Override
    public Object first() {
        // TODO Auto-generated method stub
        return concreteAggregate.get(0);
    }

    @Override
    public Object next() {
        // TODO Auto-generated method stub
        current++;
        if (current >= concreteAggregate.count()) {
            return null;
        }
        return concreteAggregate.get(current);
    }

    @Override
    public boolean isDone() {
        // TODO Auto-generated method stub
        return current > concreteAggregate.count() ? true : false;
    }

    @Override
    public Object currentItem() {
        // TODO Auto-generated method stub
        return concreteAggregate.get(current);
    }

}

/**
 * 客户端
 * @author chenguyan
 * @date 2017年6月16日
 */
public class Client {
    
    public static void main(String[] args) {
        ConcreteAggregate concrete = new ConcreteAggregate();
        concrete.add("a");
        concrete.add("b");
        concrete.add("c");
        concrete.add("d");
        concrete.add("e");
        
        Iterator ite = new ConcreteIterator(concrete);
        
        System.out.println(ite.first().toString());
        
        while (!ite.isDone()) {
            Object item = ite.next();
            System.out.println(item != null ? item.toString() : "");
        }
    }

}

为什么会采用抽象类的方式来实现迭代器呢?因为可以有不同的迭代顺序,从前向后、从后向前等,所以随意新增迭代器的实现类来达到迭代顺序的不同,而且客户端修改部分较少。

十三、单例模式

介绍:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

/**
 * 双重锁定
 * @date 2017年7月3日
 */
public class Singleton {
    
    private static Singleton singleton;
    private static Object syncObj = new Object();
    
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (syncObj) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }

}

十四、桥接模式

介绍:按各自的功能进行分类,使他们可以独立运行。

举例:手机的品牌与软件都会存在不兼容的情况,这是因为手机厂商即做硬件又做软件,没有统一的标准。如果有一个统一的硬件厂商设计标准,手机厂商只负责软件,这样每个手机厂商开发的软件就不存在不兼容的情况了。

图片描述

十五、命令模式

介绍:将请求命令封装成对象,从而使你可用不同的请求命令来操作对象。

图片描述

/**
 * 命令
 * @date 2017年8月11日
 */
public abstract class Command {
    
    private Recipient recipient;

    public void setRecipient(Recipient recipient) {
        this.recipient = recipient;
    }
    
    public abstract void doing();

}

/**
 * 烤菜命令
 * @date 2017年8月11日
 */
public class RoastVegetablesCommand extends Command {

    private Recipient recipient;
    
    @Override
    public void setRecipient(Recipient recipient) {
        // TODO Auto-generated method stub
        this.recipient = recipient;
    }
    
    @Override
    public void doing() {
        // TODO Auto-generated method stub
        System.out.println("正在烤菜");
    }
    
}

/**
 * 烤肉命令
 * @date 2017年8月11日
 */
public class RoastMeatCommand extends Command {
    
    private Recipient recipient;
    
    @Override
    public void setRecipient(Recipient recipient) {
        // TODO Auto-generated method stub
        this.recipient = recipient;
    }

    @Override
    public void doing() {
        // TODO Auto-generated method stub
        System.out.println("正在执行烤肉");
    }

}

/**
 * 接收人
 * @date 2017年8月11日
 */
public class Recipient {
    
    private String name;
    private String job;
    
    public Recipient(String name, String job) {
        this.name = name;
        this.job = job;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getJob() {
        return job;
    }
    public void setJob(String job) {
        this.job = job;
    }
    
}

/**
 * 服务员
 * @date 2017年8月11日
 */
public class Waiter {
    
    private List<Command> commandList = new ArrayList<Command>();
    
    public void addOrder(Command command) {
        if (!commandList.contains(command)) {
            commandList.add(command);
        }
    }
    
    public void notifyCommand() {
        for (Command command : commandList) {
            command.doing();
        }
    }

}

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        Recipient recipient = new Recipient("大厨", "大厨");
        
        Command roastMeatCommand = new RoastMeatCommand();
        Command roastVegetablesCommand = new RoastVegetablesCommand();
        
        roastMeatCommand.setRecipient(recipient);
        roastVegetablesCommand.setRecipient(recipient);
        
        Waiter waiter = new Waiter();
        waiter.addOrder(roastMeatCommand);
        waiter.addOrder(roastVegetablesCommand);
        waiter.notifyCommand();
    }

}

设计原则

一、迪米特法则

介绍:如果两个类不必彼此通信,那么这两个类就不应当发生直接的相互作用。强调类之间的松耦合。

反射机制

一、调用私有域和方法(setAccessible)

class Employee{

    private int id;
    private String name;
    private int age;
    
    public Employee(){}
    
    public Employee(int id, String name, int age){
        this.id = id;
        this.name = name;
        this.age = age;
    }

    private void setId(int id){
       this.id = id;
    }
    
    private int judge(int id){
        return this.id - id;
    }
    
    private String sayHalo(String name){
        return "Halo" + name;
    }
    
}
public class PrivateTest{

     public static void main(String[] args){
         Employee em = new Employee(1, "Alex", 22);

         Class<?> emClass =  em.getClass();
 
         Method judgeMethod = emClass.getDeclaredMethod("judge", new Class[]{Integer.TYPE}); //获取声明的方法
         judgeMethod.setAccessible(true); //使成员可以访问
 
         Method[] allMethods = emClass.getDeclaredMethods(); //获取所有声明的方法
         AccessibleObject.setAccessible(allMethods, true);
        
         judgeMethod.invoke(em, new Object[]{3}); //通过反射访问
 
         //or...
         for(Method method : allMethods){
          ...
         }
     }
     
}

Whoami
1.4k 声望17 粉丝