设计模式 Java版
设计模式(Design Pattern)的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。正确使用设计模式具有以下优点:
- 可以提高程序员的思维能力、编程能力和设计能力。
- 使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
- 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。
- 根据目的用途来划分,可分为创建型模式、结构型模式和行为型模式 3 种。
- 创建型模式:用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”。GoF 中提供了单例、原型、工厂方法、抽象工厂、建造者等 5 种创建型模式。
- 结构型模式:用于描述如何将类或对象按某种布局组成更大的结构,GoF 中提供了代理、适配器、桥接、装饰、外观、享元、组合等 7 种结构型模式。
- 行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责。GoF 中提供了模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器等 11 种行为型模式。
- 根据作用范围来分,可分为类模式和对象模式两种。
- 类模式:用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译时刻便确定下来了。GoF中的工厂方法、(类)适配器、模板方法、解释器属于该模式。
- 对象模式:用于处理对象之间的关系,这些关系可以通过组合或聚合来实现,在运行时刻是可以变化的,更具动态性。GoF 中除了以上 4 种,其他的都是对象模式。
0x01 单例模式
单例模式是运用最广泛的设计模式之一,应用单例模式的类在整个程序中只有一个实例存在。通常用于很消耗资源的类,比如线程池,缓存,网络请求,IO操作,访问数据库等。为保证单例模式的线程安全,采用 双重校验。示例代码:
1 2 3 4 5 6 7 8 9 10
| public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }
|
0x02 Builder模式
将一个复杂对象的构建与对象的参数或部件的创建分离,达到解耦的目的。用户不用知道内部构建细节,可以更好的控制构建流程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Person { private int ID; private Person(Builder builder) { this.ID = builder.ID; } public static class Builder { private int ID; public Builder setID(int ID) { this.ID = ID; return this; } public Person build() { return new Person(this); } } }
Person.Builder buider = new Person.Builder(); buider.setID(1001); Person p1 = buider.build();
|
0x03 工厂模式
工厂模式是创建型模式,多用于需要生成复杂对象的地方。用new就可以完成创建的对象就无需使用。工厂模式降低了对象之间的耦合度,由于工厂模式依赖抽象的架构,实例化的任务交由子类去完成,所以有很好的扩展性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
interface Vehicle { void trip(); }
class QQ implements Vehicle { @Override public void trip() { System.out.println("QQ飞车..."); } }
class BenZ implements Vehicle { @Override public void trip() { System.out.println("奔驰跑车..."); } }
class VehicleFactory { public static final int QQ = 0x0001; public static final int BEN_Z = 0x0002;
public static final Vehicle buildVehicle(int type) { if (QQ == type) { return new QQ(); } else if (BEN_Z == type) { return new BenZ(); } return null; } }
public class FactoryTest { public static void main(String[] args) { Vehicle vehicle = VehicleFactory.buildVehicle(VehicleFactory.QQ); vehicle.trip(); } }
|
0x04 观察者模式
让观察者和被观察者逻辑分开。使得UI层和业务逻辑清晰。
定义一个观察者:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class PersonObserver implements Observer { static final String TAG = PersonObserver.class.getSimpleName(); String name;
public PersonObserver (String name) { this.name = name; }
@Override public void update(Observable observable, Object o) { Log.d(TAG,name + " 接收到通知啦 "+ o); } }
|
定义一个被观察者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class PersonObservable extends Observable { List<PersonObserver> list = new ArrayList<>(); public void addObserver(PersonObserver observer) { list.add(observer); }
public void removeObserver(PersonObserver observer) { if (list.contains(observer)){ list.remove(observer); } } public void notify(String info) { for (PersonObserver observer : list) { observer.update(this, info); }; } }
|
注册和通知
1 2 3 4 5 6
| PersonObserver xiaoMing = new PersonObserver("xiaoMing");
PersonObservable pObservable = new PersonObservable(); pObservable.addObserver(xiaoMing);
pObservable.notify("notify!");
|
0x05 代理模式(Proxy)
代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。
代理类和委托类(被代理类)应该共同实现一个接口,或者是共同继承某个类。
1)静态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
interface DAO { void build(); }
class PartnerDAO implements DAO { @Override public void build() { System.out.println("PartnerDAO..."); } }
class DAOProxy implements DAO { private DAO dao;
public DAOProxy(DAO dao) { this.dao = dao; }
@Override public void build() { System.out.println("build start..."); long start = System.currentTimeMillis(); dao.build(); long end = System.currentTimeMillis(); System.out.println("build start..."); System.out.println("执行耗费时间:" + (end - start)); } }
public class ProxyTest { @Test public void test1() { PartnerDAO dao = new PartnerDAO(); DAOProxy daoProxy = new DAOProxy(dao); daoProxy.build(); } }
|
2)动态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
interface DAO { void build(); }
class PartnerDAO implements DAO { @Override public void build() { System.out.println("PartnerDAO build()."); } }
interface B { int work(boolean free); }
class PartnerB implements B { @Override public int work(boolean free) { System.out.println("PartnerB work()."); return 2; } }
class DAOHandler implements InvocationHandler { private Object target;
public DAOHandler(Object target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method.getName() + " start..."); long start = System.currentTimeMillis(); Object result = method.invoke(target, args); long end = System.currentTimeMillis(); System.out.println(method.getName() + " start..."); System.out.println("执行耗费时间:" + (end - start)); return result; } }
public class ProxyTest { @Test public void test1() { PartnerDAO dao = new PartnerDAO(); ClassLoader loader = dao.getClass().getClassLoader(); Class<?>[] interfaces = dao.getClass().getInterfaces(); DAOHandler h = new DAOHandler(dao); DAO a1 = (DAO) Proxy.newProxyInstance(loader, interfaces, h); a1.build(); }
@Test public void test2() { PartnerB pb = new PartnerB(); ClassLoader loader = pb.getClass().getClassLoader(); Class<?>[] interfaces = pb.getClass().getInterfaces(); DAOHandler h = new DAOHandler(pb); B b = (B) Proxy.newProxyInstance(loader, interfaces, h); b.work(true); } }
|
静态代理和动态代理的区别,静态代理一个代理类针对一个委托类,动态代理一个代理类可利用反射机制代理多个委托类。
静态代理在代码编译时就确定了委托类的类型,动态代理在代码运行时才动态加载委托类,运行时才确定委托类的类型。
使用场景:比如RPC框架和Spring AOP机制。
0x06 迭代器模式
根据传入的列表类数据提供一个额外的遍历方法。
1 2 3 4
| while (cursor.hasNext()) { Log.d("Cursor",cursor.next()); }
|
0x07 适配器模式( ListView 与 Adapter )
将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作