设计模式(视频总结)
[TOC]
一、简单工厂模式(Simple Factory)
简单工厂模式:
简单工厂模式属于类的创建型模式,又叫静态工厂方法模式,通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
角色:
1.工厂角色
简单工厂的核心 ,它负责实现创建所有实例的内部逻辑,工厂类可以被外界直接调用创建所需产品对象。
2.抽象角色
简单工厂模式所创建的所有对象的父类,它负责描述所有实例的公共接口
3.具体产品角色
简单工厂所创建的具体实例对象。
//工厂角色(版本一)
public class FruitFactory {
public static Fruit getApple(){
return new Apple();
}
public static Fruit getBanana(){
return new Banana();
}
}
//抽象角色
public interface Fruit {
public void get();
}
//产品
public class Apple implements Fruit{
@Override
public void get() {
System.out.println("采集苹果");
}
}
//产品
public class Banana implements Fruit{
@Override
public void get() {
System.out.println("采集香蕉");
}
}
//测试函数
public class Main {
public static void main(String[] args) {
Fruit apple = FruitFactory.getApple();
Fruit banana = FruitFactory.getBanana();
apple.get();
banana.get();
}
}
以上就是一个简单工厂模式
现对工厂角色进行改进:
//版本二(常用)
public static Fruit getFruti(String type) throws InstantiationException, IllegalAccessException{
if(type.equalsIgnoreCase("apple")){
return Apple.class.newInstance();
}else if(type.equalsIgnoreCase("banana")){
return Banana.class.newInstance();
}else{
System.out.println("找不到响应的类");
return null;
}
}
再改进
//版本三
public static Fruit getFruit(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
Class> fruit = Class.forName(type);//type必须是类的完全限定名
return (Fruit) fruit.newInstance();
}
//版本三的测试程序
Fruit apple = FruitFactory.getFruit("simpleFactory_4.Apple");
Fruit banana = FruitFactory.getFruit("simpleFactory_4.Banana");
apple.get();
banana.get();
二、工厂方法模式(Factory Method)
意图:
定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法是一个类的实例化延迟到其子类。
适用性:
- 当一个类不知道它所必须创建的对象的类的时候。
- 当一个类希望由它的子类来制定它所创建的对象的时候。
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望哪一个帮助子类是代理这一信息局部化的时候。
角色:
- 抽象工厂角色
工厂方法模式的核心,任何工厂类都必须实现这个借口。
- 具体工厂角色
具体工厂类是抽象工厂的一个实现,负责实例化产品对象。 - 抽象角色
工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口 - 具体产品角色
工厂方法模式所创建的具体的实例对象
代码:
//抽象工厂角色
public interface FruitFactory {
public Fruit getFruit();
}
//具体工厂角色
public class AppleFactory implements FruitFactory {
@Override
public Fruit getFruit() {
return new Apple();
}
}
//具体工厂角色
public class BananaFactory implements FruitFactory {
@Override
public Fruit getFruit() {
return new Banana();
}
}
//抽象角色
public interface Fruit {
public void get();
}
//具体产品角色
public class Apple implements Fruit{
@Override
public void get() {
System.out.println("采集苹果");
}
}
//具体产品角色
public class Banana implements Fruit{
@Override
public void get() {
System.out.println("采集香蕉");
}
}
//测试方法
public class Main {
public static void main(String[] args) {
Fruit apple = new AppleFactory().getFruit();
apple.get();
Fruit banana = new BananaFactory().getFruit();
banana.get();
}
}
工厂方法模式和简单工厂模式的比较
- 工厂方法模式与简单工厂模式在结构上的不同不是很明显。工厂方法类的核心是一个抽象的工厂类,而简单工厂模式把核心放在一个具体的类上。
- 工厂方法模式之所以有一个别名叫多态工厂模式是因为具体工厂类都有共同的接口,或者有共同的抽象父类。
- 当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的复合“开放-封闭”原则,而简单工厂模式再添加新产品对象后不得不修改工厂方法,扩展性不是很好。
- 工厂方法模式退化后可以演变成简单工厂模式。
三、 抽象工厂模式(Abstract Factory)
抽象工厂模式是所有形态的工厂模式中最为抽象和最具有一般性的,抽象工厂模式可以指定向客户端提供一个接口,使得客户端不必指定产品具体类型的情况下,能够创建产品族的产品对象。
意图:
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
适用性:
- 一个系统要独立于它的产品的创建、组合和表示时。
- 一个系统要有多个产品系列中的一个来配置时。
- 当你要强调一系列相关的产品对象的设计以便进行联合使用时。
- 当你提供一个产品库,而只想显示它们的接口而不是实现时。
角色:
- 抽象工厂角色
抽象工厂模式的核心,包含对多个产品结构的申明,任何工厂类都必须实现这个接口。
- 具体工厂角色
具体工厂角色类是抽象工厂的一个实现负责实例化某个产品族的产品对象。 - 抽象角色
抽象模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口 - 具体产品角色
抽象模式所创建的具体实例对象
抽象工厂方法对应产品结构,具体工厂对应产品族。
//抽象工厂角色
public interface FruitFactory {
//实例化苹果
public Fruit getApple();
//实例化Banana
public Fruit getBanana();
}
//具体工厂角色
public class NorthFruitFactory implements FruitFactory {
@Override
public Fruit getApple() {
return new NorthApple();
}
@Override
public Fruit getBanana() {
return new NorthBanana();
}
}
//具体工厂角色
public class SouthFruitFactory implements FruitFactory {
@Override
public Fruit getApple() {
return new SouthApple();
}
@Override
public Fruit getBanana() {
return new SouthBanana();
}
}
//抽象角色
public interface Fruit {
public void get();
}
//抽象角色
public abstract class Apple implements Fruit{
public abstract void get();
}
//抽象角色
public abstract class Banana implements Fruit{
public abstract void get();
}
//具体产品角色
public class NorthApple extends Apple{
@Override
public void get() {
System.out.println("采集北方苹果");
}
}
//具体产品角色
public class NorthBanana extends Banana{
@Override
public void get() {
System.out.println("采集北方香蕉");
}
}
//具体产品角色
public class SouthApple extends Apple{
@Override
public void get() {
System.out.println("采集南方苹果");
}
}
//具体产品角色
public class SouthBanana extends Banana{
@Override
public void get() {
System.out.println("采集南方香蕉");
}
}
//测试方法
public class Main {
public static void main(String[] args) {
NorthFruitFactory northFruitFactory = new NorthFruitFactory();
Fruit northApple = northFruitFactory.getApple();
northApple.get();
Fruit northBanana = northFruitFactory.getBanana();
northBanana.get();
System.out.println("**********");
SouthFruitFactory southFruitFactory = new SouthFruitFactory();
Fruit southApple = southFruitFactory.getApple();
southApple.get();
Fruit southBanana = southFruitFactory.getBanana();
southBanana.get();
}
}
如果要新增的话,我们只需要添加一个产品链
比如我们如果还有一个温室苹果和温室香蕉的话,需要新增以下类:
GreenhouseApple.java
GreenhouseBanana.java
GreenhouseFruitFactory.java
这样既可新增一个产品链。
但是如果需要添加一个新的产品,那么我们必须修改所有的工厂方法,新增get方法。
四、 单例模式(Singleton)
单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象。
定义:
保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。
适用性:
- 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
- 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能实现一个扩展的实例时。
1. 饿汉式
public class Person {
public static final Person person = new Person();
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//构造函数私有化
private Person(){}
//提供一个全局的静态方法
public static Person getPerson(){
return person;
}
}
//测试函数
public class Main {
public static void main(String[] args) {
Person person_1 = Person.getPerson();
System.out.println(person_1.hashCode());
Person person_2 = Person.getPerson();
System.out.println(person_2.hashCode());
}
}
2. 懒汉式(非线程安全)
public class Person2 {
private static Person2 person;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//构造函数私有化
private Person2(){}
//提供一个全局的静态方法
public static Person2 getPerson(){
if(person == null){
person = new Person2();
}
return person;
}
}
测试函数同上
3.双重检查(线程安全)
public class Person3 {
private static Person3 person;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//构造函数私有化
private Person3(){}
//提供一个全局的静态方法
public static Person3 getPerson(){
if(person == null){
synchronized (Person3.class){
if(person == null){
person = new Person3();
}
}
}
return person;
}
}
测试方法同上
五、 原型模式(Prototype)
原型模式是一种对象创建型模式,它采用复制原型对象的方法来创建对象的实例。使用原型模式创建的实例,具有与原型一样的数据。
- 由原型对象自身创建目标对象,也就是说,对象创建这一动作发自原型对象本身。
- 目标对象是原型对象的一个克隆。也就是说,通过原型对象模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。
- 根据对象克隆深度层次的不同,有浅度克隆与深度克隆。
适用性:
当要实例化的类实在运行时刻指定时,例如通过动态装载;或者为了避免创建一个与产品类层次平行的工厂类层次是;或者当一个类的实例只能有几种不同状态中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
实现方法:
- 实现Cloneable接口
- 编写clone方法
代码演示:
public class Person implements Cloneable{
private String name;
private int age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Person clone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
//测试函数
public class Main {
public static void main(String[] args) {
Person person1 = new Person();
person1.setName("王小二");
person1.setAge(23);
person1.setSex("男");
Person person2 = person1;
Person person3 = person1.clone();
System.out.println("person1:" + person1.hashCode() + " " +
person1.getName() + " " + person1.getAge() + " " + person1.getSex());
System.out.println("person2:" + person2.hashCode() + " " +
person2.getName() + " " + person2.getAge() + " " + person2.getSex());
System.out.println("person3:" + person3.hashCode() + " " +
person3.getName() + " " + person3.getAge() + " " + person3.getSex());
}
}
运行结果:
person1:705927765 王小二 23 男
person2:705927765 王小二 23 男
person3:366712642 王小二 23 男
浅度克隆:如果Person中的某个属性是一个引用值的话,浅度克隆不会克隆这个引用对象。
深度克隆:克隆Person中所有的对象。
以上是浅度克隆,如果要使用深度克隆,可以手动在clone中复制引用对象完成深度克隆。
六、 建造者模式(Builder)
建造者模式也称生成器模式,是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态的创建具有复合属性的对象。
意图:
将一个复杂对象的构建与他的表示分离,是的同样的构建过程可以创建不同的表示。
适用性:
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 当构造过程必须允许被构造的对象有不同的表示时。
代码示例:
//
public class House {
//底板
private String floor;
//墙
private String wall;
//屋顶
private String housetop;
//省略get、set方法
}
//施工队接口
public interface HouseBuilder {
//修地板
public void makeFloor();
//修墙
public void makeWall();
//修屋顶
public void makeHousetop();;
public House getHouse();
}
//具体施工队
public class PingFangBuilder implements HouseBuilder {
House house = new House();
@Override
public void makeFloor() {
house.setFloor("平方--->地板");
}
@Override
public void makeWall() {
house.setWall("平方--->墙");
}
@Override
public void makeHousetop() {
house.setHousetop("平方--->房顶");
}
@Override
public House getHouse() {
return house;
}
}
//设计者
public class HouseDicretor {
private HouseBuilder builder;
public HouseDicretor(HouseBuilder builder) {
this.builder = builder;
}
public void makeHouse(){
builder.makeFloor();
builder.makeWall();
builder.makeHousetop();
}
}
//测试方法
public class Main {
public static void main(String[] args) {
//客户直接造房子
House house = new House();
house.setWall("墙");
house.setFloor("底板");
house.setHousetop("屋顶");
//由工程队来修
HouseBuilder builder = new PingFangBuilder();
//设计者来做
HouseDicretor dicretor = new HouseDicretor(builder);
dicretor.makeHouse();
House pingfangHouse = builder.getHouse();
System.out.println(pingfangHouse.getFloor());
System.out.println(pingfangHouse.getWall());
System.out.println(pingfangHouse.getHousetop());
}
}
八、 装饰模式(Decorator)
装饰模式又叫包装模式。通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案。
角色:
- 抽象组件角色: 一个抽象接口,是被装饰类和装饰类的父接口。
- 具体组件角色:为抽象组件的实现类。
- 抽象装饰角色:包含一个组件的引用,并定义了与抽象组件一致的接口。
- 具体装饰角色:为抽象装饰角色的实现类。负责具体的装饰。
意图:
动态的给一个对象添加一些额外的职责。
适用性:
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 处理那些可以撤销的职责
- 当不能采用生成子类的方法进行扩充时,一种情况是可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况是可能是因为类定义被隐藏,或类定义不能用于生成子类。
代码演示:
//抽象组件角色
public interface Car {
public void show();
public void run();
}
//具体组件角色
public class RunCar implements Car {
@Override
public void show() {
this.run();
}
@Override
public void run() {
System.out.println("可以跑");
}
}
//抽象装饰角色
public abstract class CarDecorator implements Car{
private Car car;
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public CarDecorator(Car car) {
this.car = car;
}
public abstract void show();
}
//具体装饰角色
public class FlyCarDecorator extends CarDecorator {
public FlyCarDecorator(Car car) {
super(car);
}
@Override
public void run() {
}
@Override
public void show() {
this.getCar().show();
this.fly();
}
public void fly(){
System.out.println("可以飞");
}
}
//具体装饰角色
public class SwimCarDecorator extends CarDecorator {
public SwimCarDecorator(Car car) {
super(car);
}
@Override
public void run() {
}
@Override
public void show() {
this.getCar().show();
this.swim();
}
public void swim() {
System.out.println("可以游");
}
}
//测试类
public class Main {
public static void main(String[] args) {
Car runCar = new RunCar();
CarDecorator flyCar = new FlyCarDecorator(runCar);
CarDecorator swimCar = new SwimCarDecorator(flyCar);
swimCar.show();
}
}
运行结果:
可以跑
可以飞
可以游
九、 策略模式(Strategy)
策略模式也是行为模式的一种,它对一系列算法加以封装,为所有算法定义一个抽象的接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,具体的算法选择交由客户端决定。
角色:
- Strategy:策略(算法)抽象。
- ConcreteStrategy:各种策略(算法)的具体实现。
- Context:策略的外部封装类,或者说策略的容器类。根据不同策略执行不同的行为。策略由外部环境决定。
适用性:
- 许多相关类仅仅是行为有异。“策略”提供一种用多个行为中的一个行为来配置一个类的方法。
- 需要使用一个算法的不同变体。例如,你可能会定义一些反应不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次是,可以使用策略模式。
- 算法使用客户不应该知道的数据,可以使用策略模式以避免暴露复杂的,预算法相关的数据结构。
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,将相关的条件分支一如它们各自的策略类中一代替这些条件语句。
代码展示:
//算法抽象
public interface Transition {
public String transition(String str);
}
//算法实现(转换为大写字母)
public class UpperCaseTransition implements Transition{
@Override
public String transition(String str) {
return str.toUpperCase();
}
}
//算法实现(转换为小写字母)
public class LowerCaseTransition implements Transition {
@Override
public String transition(String str) {
return str.toLowerCase();
}
}
//策略的外部封装
public class Context implements Transition {
private Transition transition;
public Context(Transition transition) {
this.transition = transition;
}
@Override
public String transition(String str) {
return transition.transition(str);
}
}
//测试类
public class Main {
public static void main(String[] args) {
Context context = new Context(new UpperCaseTransition());
System.out.println(context.transition("abcdef"));
Context context_1 = new Context(new LowerCaseTransition());
System.out.println(context_1.transition("ABCDEF"));
}
}
运行结果:
ABCDEF
abcdef
策略模式的优点:
- 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。
- 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或
行为变得不可能。 - 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办
法还要原始和落后。
缺点:
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
- 策略模式造成很多的策略类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。
十、观察者模式(Observer)
观察者模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。
观察者模式提供给关联对象一种同步通信的手段,是某个对象与依赖它的其他对象之间保持状态同步。
角色:
- Subject(被观察者):被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。
- ConcreteSubject:被观察者的具体实现。包含一些基本的属性状态及其他操作。
- Observer(观察者):接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。
- ConcreteObserver:观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。
代码示例:
//被观察者
public class Person extends Observable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
this.setChanged();
this.notifyObservers();
}
}
//观察者
public class MyObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("对象发生变化");
}
}
//测试函数
public class Main {
public static void main(String[] args) {
Person person = new Person();
//注册观察者
person.addObserver(new MyObserver());
person.setName("王二小");
}
}
观察者模式典型应用:
- 侦听时间驱动程序设计中的外部事件
- 侦听/件事某个对象的状态变化
- 发布者/订阅者(publicsher/subscriber)模型中,当一个外部事件被触发是,通知列表中的订阅者。
适用性:
- 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中以使它们可以独立地改变和复用。
- 当对一个对象那个的改变需要同时改变其他对象,而不知道具体对象有待改变,
- 当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,你不希望这些对象是紧密耦合的。
十一、 享元模式(Flyweight)
享元模式是构造型模式之一,它通过与其他类似对象共享数据来减小内存占用。
角色:
- 抽象享元角色: 所有具体享元类的父类,规定一些需要实现的公共接口。
- 具体享元角色: 抽象享元角色的具体实现类,并实现了抽象享元角色规定的方法。
- 享元工厂角色: 负责创建和管理享元角色。
适用性:
- 一个程序使用的大量的对象。
- 完全由于使用大量对象,造成很大的存储开销。
- 对象的大多数状态都可以变为外部状态。
代码示例:
(本例中没有抽象享元角色)
//具体享元角色
public class MyCharacter {
private char mychar;
public MyCharacter(char mychar ) {
this.mychar = mychar;
}
public void display(){
System.out.println(mychar);
}
}
//享元工厂角色
public class MyCharacterFactory {
private Map pool;
public MyCharacterFactory() {
pool = new HashMap();
}
//享元模式核心内容
public MyCharacter getMyCharacter(Character character){
MyCharacter mychar = pool.get(character);
if(mychar == null){
mychar = new MyCharacter(character);
pool.put(character, mychar);
}
return mychar;
}
}
//测试函数
public class Main {
public static void main(String[] args) {
//创建工厂
MyCharacterFactory mcf = new MyCharacterFactory();
//从工厂中取出
MyCharacter myChar1 = mcf.getMyCharacter('a');
MyCharacter myChar2 = mcf.getMyCharacter('b');
MyCharacter myChar3 = mcf.getMyCharacter('a');
myChar1.display();
myChar2.display();
myChar3.display();
System.out.println(myChar1.hashCode() + " " + myChar2.hashCode() + " " + myChar3.hashCode());
}
}
运行结果:(结果说明我们创建的myChar1和myChar3是同一个对象)
a
b
a
705927765 366712642 705927765
十二、 代理模式(proxy)
代理模式是构造性的是耳机模式之一,它可以为其他对象提供一种代理以控制对这个对象的一种访问。
所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。
角色:
- subject(抽象主题角色):真实主题与代理主题的共同接口。
- RealSubject(真实主题角色):定义了代理角色所代表的真实对象。
- Proxy(代理主题角色):含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真实主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。
适用性:
在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy模式,下面是一些可以使用Proxy模式常见情况:
- 远程代理(Remote Proxy)为一个对象在不同的地址空间提供局部代表
代码演示:
//抽象主题角色:
public interface Subject {
public void sailBook();
}
//真实主题角色
public class RealSubject implements Subject {
@Override
public void sailBook() {
System.out.println("买书");
}
}
//代理主题角色
public class ProxySubject implements Subject {
private RealSubject realSubject;
public ProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
public void Discount(){
System.out.println("打折");
}
public void Vouchers(){
System.out.println("赠送代金券");
}
@Override
public void sailBook() {
this.Discount();
if(this.realSubject == null){
realSubject = new RealSubject();
}
realSubject.sailBook();
this.Vouchers();
}
}
//测试函数
public class Main {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
ProxySubject ps = new ProxySubject(realSubject);
ps.sailBook();
}
}
运行结果:
打折
买书
赠送代金券
动态代理
代码示例:
//抽象主题角色:
public interface Subject {
public void sailBook();
}
//真实主题角色
public class RealSubject implements Subject {
@Override
public void sailBook() {
System.out.println("买书");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyHandler implements InvocationHandler {
private RealSubject realSubject;
public void setRealSubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
public void Discount(){
System.out.println("打折");
}
public void Vouchers(){
System.out.println("赠送代金券");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
Discount();
result = method.invoke(realSubject, args);
Vouchers();
return result;
}
}
//测试函数
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
MyHandler myHandler = new MyHandler();
myHandler.setRealSubject(realSubject);
Subject proxySubject =
(Subject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
realSubject.getClass().getInterfaces(), myHandler);
proxySubject.sailBook();
}
}
十三、 外观模式(Facade)
外观模式为一组具有类似功能的类群,比如类库、子系统等等,提供一个一致的简单界面,这个一致的简单界面被称作facade。
适用性:
当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得也来越复杂。大多数模式使用时都会产生更多更小的类,这使得子系统更具有可重用性,也跟你容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来了一些使用上的困难。Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过facade层。
客户程序与抽象类的和实现部分之间存在很大的依赖性。引入facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。如果子系统之间相互依赖的,你可以让它们仅通过facade进行通讯,从而简化它们之间的依赖关系。
角色:
- Facade:为调用方定义简单的调用接口。
- Clients:调用者。通过Facade接口调用提供某功能的内部类群。
- Packages:功能提供者,指提供功能的类群、模块、或者子系统。
代码示例:
//功能提供者
public class SystemA {
/**
* A子系统实现功能
*/
public void doSomething(){
System.out.println("实现A子系统功能");
}
}
//功能提供者
public class SystemB {
/**
* B子系统实现功能
*/
public void doSomething(){
System.out.println("实现B子系统功能");
}
}
//Facade
public class Facade {
private SystemA systemA;
private SystemB systemB;
public Facade() {
systemA = new SystemA();
systemB = new SystemB();
}
public void doSomething(){
this.systemA.doSomething();
this.systemB.doSomething();
}
}
//测试函数
public class Main {
public static void main(String[] args) {
//常规方法
//实现A子系统功能
SystemA systemA = new SystemA();
systemA.doSomething();
//实现B子系统功能
SystemB systemB = new SystemB();
systemB.doSomething();
//外观模式
Facade facade = new Facade();
facade.doSomething();
}
}