设计模式
此文章部分来于网络,为了学习总结。
一、原型模式(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){
...
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。