文章链接:http://c.biancheng.net/design_pattern/
设计模式的本质是对面向对象设计原则运用,是对类的封装、继承和多态以及类的关联关系和组合关系的充分理解。优点:
软件设计模式可以使人们更加简洁方便的复用成功的设计和体系结构。
最关键的包括如下4个主要部分
设计模式有两种分类方法:根据目的来分和根据模式的作用范围来分。
根据模式是用来完成什么工作目的的,这种凡是分为创建型模式、结构型模式和行为型模式3种。
根据模式主要用于类上还是对象上来分,可以分为类模式和对象模式。
范围\目的 | 创建型模式 | 结构型模式 | 行为型模式 |
---|---|---|---|
类模式 | 工厂方法 | (类)适配器 | 模板方法、解释器 |
对象模式 | 单例 原型 抽象工厂 建造者 |
代理 (对象)适配器 桥接 装饰 外观 享元 组合 |
策略 命令 职责链 状态 观察者 中介者 迭代器 访问者 备忘录 解释器 |
在软件系统中,类不是孤立存在的,类与类之间存在各种关系。
//人打电话
public class Person{
private String name;
//打电话
public void call(MobilePhone mp){
//通过方法参数来访问另一个类
mp.call("打电话");
}
}
//电话
public class MobilePhone{
public void call(String message){
//打电话一系列操作,不详细介绍
...
}
}
public class Teacher{
String name;
//一个老师可以有多个学生
List students;
}
public class Student{
String name;
//一个学生可以有多个老师,语文、数学...老师
List teachers;
}
public class University{
String name ;
//一个大学有多个老师
List teachers;
}
//成员变量,老师
public class Teacher{
String name;
}
//头和嘴关系,头
public class Head{
Mouth mouth;
Eye eye;
}
public class Mouth{
//嘴的属性...
}
//人
public class Person{
Integer age;
String sex;
String name;
}
public class Student extends Person{
//学生编号
Integer studentNo;
//学习
public void study(){
//...学习
}
}
public class Teacher extends Person{
//老师编号
Integer teacherNo;
//教学
public void teach(){
//教学..
}
}
//交通工具
public interface Vehicle {
public void move();
}
//汽车实现交通工具接口类
public class Car implements Vehicle{
@Override
public void move() {
// TODO Auto-generated method stub
}
}
//火车实现交通工具接口类
public class Train implements Vehicle{
@Override
public void move() {
// TODO Auto-generated method stub
}
}
在软件开发过程中,为了提高系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序要都需要遵循7条原则来开发,从而提高开发效率节约研发成本和维护成本。
开闭原则:软件开发过程中,软件实体应当对扩展开放,对修改关闭。也就是当应用需求改变的时候,在不修改软件实体的源码或者二进制码的情况下,可以扩展模块的功能,使其满足新的需求。
// -- windows主题展示,抽象类,将接口抽象画
public abstract class Subject {
public abstract void display();
}
//具体的主题是子类
public class SubjectOne extends Subject {
public void display(){
System.out.println("第一个主题");
}
}
//具体的主题是子类
public class SubjectTwo extends Subject {
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("第二个主题");
}
}
主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,以及其中蕴含的原理。它是继承复用的基础,反应了基类与子类之间的关系,是对开闭原则的补充,是对抽象化的具体步骤的规范。
里氏替换原则的作用:
//动物
public class Animal {
//行走速度
private double runSpeed;
//distance公里所需时间
public double getRunTime(double distance){
return distance/ runSpeed;
}
public void setRunSpeed(double runSpeed) {
this.runSpeed = runSpeed;
}
}
//鸟类继承动物,但是鸟类是飞行,鸟类扩展了动物的特性,相当于子类的新特性,而且不会影响基类的操作
public class Bird extends Animal {
//鸟类特性 fly速度
private double flySpeed;
//鸟类飞行distance公里所需时间
public double getFlyTime(double distance){
return distance / flySpeed;
}
public void setSpeed(double flySpeed) {
this.flySpeed = flySpeed;
}
}
//燕子继承鸟类
public class Swallow extends Bird {
}
//几维鸟继承动物,几维鸟是鸟但是不会飞
public class BrownKiwi extends Animal {
}
public class Main {
public static void main(String[] args) {
Bird swallow = new Swallow();
swallow.setSpeed(120);
Animal kiwi = new BrownKiwi();
kiwi.setRunSpeed(10);
System.out.println("如果飞行或者行走300公里");
System.out.println("燕子飞行300公里用时"+swallow.getFlyTime(300)+"小时");
System.out.println("几维鸟行走300公里用时"+kiwi.getRunTime(300)+"小时");
}
}
高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想就是:要面向接口编程,不要面向实现编程。这里的抽象代表接口或者抽象类,而细节指具体的实现。
依赖倒置原则是实现开闭原则的重要途径之一,降低了客户与实现模块的耦合度。
依赖倒置原则的作用:
依赖倒置原则的实现方法:
//顾客购物场景
//商店卖东西
//无论顾客选择那家商店,商店(Store)都有一个sell()接口,顾客(Customer)都有个shopping()购物接口。
//商店卖东西接口类
public Interface Store{
//卖东西
public String sell();
}
public class Customer{
private String name;
public String shopping(Store shop){
//购物
return "顾客购买东西"+shop.sell();
}
public Customer(String name){
this.name = name;
}
}
//鞋店也是商店,卖鞋,实现了商店接口
public class ShoeStore implements Store{
public String sell(){
return "耐克,艾迪达斯,鸿星尔克...各种各样的鞋子";
}
}
//衣服店也是商店,卖衣服,实现了商店接口
public class ClothesStore{
public String sell(){
return "卫衣,毛衣,衬衫,短袖...各种衣服";
}
}
public class Test{
public static void main(String args[]){
//顾客
Customer custom = new Customer("张三");
//购买鞋子
custom.shopping(new ShoeStore());
//购买衣服
custom.shopping(new ClothesStore());
}
}
//运行结果:
//张三:
//顾客购买东西:售卖:耐克,艾迪达斯/,鸿星尔克...各种各样的鞋子
//顾客购买东西:卫衣,毛衣,衬衫,短袖...各种衣服
单一职责原则规定,一个类有且仅有一个引起变化的原因,否则这个类就应该被拆分。对象不应该承担太多职责,如果一个对象承担太多职责则会有以下两个缺点:
单一职责的有点:
/**
* 分析:大学学生工作主要包括学生生活辅导和学生学业指导两个方面的工作,其中生活辅导主要包括班委建设、出勤统计、心理辅导、费用催缴、班级管理等工作,学业指导主要包括专业引导、学习辅导、科研指导、学习总结等工作。如果将这些工作交给一位老师负责显然不合理,正确的做 法是生活辅导由辅导员负责,学业指导由学业导师负责。
* 总的来说:学生工作分为两块,生活辅导员,学业辅导员
**/
//学生工作
public class StudentWork{
//生活辅导员
public LifeTeacher lifeTeacher;
//学业辅导员
public TeachTeacher teachTeacher;
}
//生活辅导主要包括班委建设、出勤统计、心理辅导、费用催缴、班级管理等工作
public class LifeTeacher{
public void 班委建设(){
//..班委极限社相关内容
}
public void 出勤统计(){
//..出勤统计相关内容
}
public void 心理辅导(){
//..心理辅导相关内容
}
public void 费用催缴(){
//..费用催缴相关内容
}
public void 班级管理(){
//..班级管理相关内容
}
}
//学业辅导员主要包括专业引导、学习辅导、科研指导、学习总结等工作
public class TeachTeacher {
public void 专业引导(){
//..专业引导相关内容
}
public void 学习辅导(){
//..学习辅导相关内容
}
public void 科研指导(){
//..科研指导相关内容
}
public void 学习总结(){
//..学习总结相关内容
}
}
接口隔离原则就是将庞大臃肿的接口拆分成更小或者更具体的接口,让接口中只包含客户感兴趣的方法。
要为各个类建立他们专用的接口,而不要试图去建立一个很庞大的接口供所有的依赖它的类去调用。
接口隔离原则和单一职责原则有相同点,都是为了提高类的内聚性、降低他们之间的耦合度,体现了封装的思想。但是两者也有不同:
接口隔离原则的优点:
接口隔离原则的实现方法:
//学生成绩管理程序一般包含插入成绩、删除成绩、修改成绩、计算总分、计算均分、打印成绩信息、査询成绩信息等功能,如果将这些功能全部放到一个接口中显然不太合理,正确的做法是将它们分别放在输入模块、统计模块和打印模块等 3 个模块中
//1.输入模块:插入成绩,修改成绩,删除成绩
//2.统计模块:计算总分,计算平均分
//3.打印模块:打印成绩信息,查询成绩信息
// 插入模块
public interface InputMoudle{
//插入成绩
public void insert();
//删除成绩
public void delete();
//修改成绩
public void update();
}
// 统计模块
public interface CountMoudle{
//计算总分
public Integer countTotalScore();
//计算平均分
public double countAvgScore();
}
// 打印模块
public interface PrintMoudle{
//打印成绩信息
public void print();
//查询成绩信息
public void search();
}
// 实现类
public class StuScoreList implements InputMoudle,CountMoudle,PrintMoudle{
private StuScoreList{}
public static InputMoudle getInputMoudle(){
return (InputMoudle)new StuScoreList();
}
public static CountMoudle getCountMoudle(){
return (CountMoudle)new StuScoreList();
}
public static PrintMoudle getPrintMoudle(){
return (PrintMoudle)new StuScoreList();
}
public void insert()
{
System.out.println("输入模块的insert()方法被调用!");
}
public void delete()
{
System.out.println("输入模块的delete()方法被调用!");
}
public void modify()
{
System.out.println("输入模块的modify()方法被调用!");
}
public void countTotalScore()
{
System.out.println("统计模块的countTotalScore()方法被调用!");
}
public void countAverage()
{
System.out.println("统计模块的countAverage()方法被调用!");
}
public void printStuInfo()
{
System.out.println("打印模块的printStuInfo()方法被调用!");
}
public void queryStuInfo()
{
System.out.println("打印模块的queryStuInfo()方法被调用!");
}
}
public class ISPtest
{
public static void main(String[] args)
{
InputModule input =StuScoreList.getInputModule();
CountModule count =StuScoreList.getCountModule();
PrintModule print =StuScoreList.getPrintModule();
input.insert();
count.countTotalScore();
print.printStuInfo();
//print.delete();
}
}
米迪特法则的定义是:如果两个软件实体无需直接通信,那么就不应当发生直接的交互调用,可以通过第三方转发该调用。其目的是为了降低类之间的耦合度,提高模块相对独立。
米迪特法则的有点:
米迪特法则的缺点:过度使用米迪特法则会使得系统产生大量的中介类,从而增加系统的复杂度,使得模块之间的通信效率降低。所以在采用米迪特法则的时候需要反复权衡,确保高内聚和低耦合的同时,保证系统的结构清晰。
米迪特法则的实现方法:
所以在运用米迪特法则的时候需要注意6点:
//明星由于全身心投入艺术,所以许多日常事务由经纪人负责处理,如与粉丝的见面会,与媒体公司的业务洽淡等。这里的经纪人是明星的朋友,而粉丝和媒体公司是陌生人,所以适合使用迪米特法则
//明星
public class Star{
private String name ;
private String getName(){
return this.name;
}
}
//粉丝
public class Fans{
private String name;
public String getName{
//获取粉丝名称
return this.name;
}
}
//公司
public class Company{
private String name;
public String getName{
//获取公司名称
return this.name;
}
}
//经纪人
public class Agent{
private Star myStar;
private Fans myFans;
private Company myCompany;
public void setStar(Star myStar){
this.myStar = mystar;
}
public void setFans(Fans myFans){
this.myFans = myFans;
}
public void setCompany(Company myCompany){
this.myCompany = myCompany;
}
public void meeting(){
System.out.println(myFans.getName +"与明星"+myStar.getName()+"见面了");
}
public void business(){
System.out.println(myCompany.getName +"与明星"+myStar.getName()+"洽谈业务了");
}
}
public class LoDtest
{
public static void main(String[] args)
{
Agent agent=new Agent();
agent.setStar(new Star("林心如"));
agent.setFans(new Fans("粉丝韩丞"));
agent.setCompany(new Company("中国传媒有限公司"));
agent.meeting();
agent.business();
}
}
// 粉丝韩丞与明星林心如见面了。
// 中国传媒有限公司与明星林心如洽淡业务。
合成复用原则要求在软件复用时,要尽量先使用组合或者聚合关系来关联实现,其次才考虑使用继承关系来实现。如果要使用继承关系,则必须严格遵循里氏替换原则。
合成复用原则的重要性,通常复用分为继承复用和合成复用两种,继承复用虽然简单和易实现的有点,但是也有缺点:
采用组合或者聚合复用时,可以将已有的对象纳入新的对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,有以下优点:
合成复用原则的实现方法:合成复用原则是通过将已有的对象纳入新对象中,作为新对象的成员来实现,新对象可以调用已有对象的功能,从而达到复用。
//分析:汽车按“动力源”划分可分为汽油汽车、电动汽车等;按“颜色”划分可分为白色汽车、黑色汽车和红色汽车等。如果同时考虑这两种分类,其组合就很多
//汽车:--移动move
// : --颜色Color:
// --白色
// --黑色
// --红色
//汽车对象将颜色对象纳入到汽车里面,作为汽车的对象来使用
public class Color{
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
public class Car{
private Color color;
public void move(){
System.out.println("汽车");
}
public Car(Color color){
this.color = color;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
public class GasoLineCar extends Car{
public GasoLineCar(Color color) {
super(color);
// TODO Auto-generated constructor stub
}
}
public class White extends Color{
}
public class Main {
public static void main(String[] args) {
Color color = new White();
color.setColor("白颜色");
Car car = new GasoLineCar(color);
System.out.println(car.getColor().getColor());
car.move();
}
}
// 白颜色
// 汽车
创建模式主要是"将对象的创建和使用分开",这样可以降低系统的耦合度,使用者不需要关注对象的创建细节,对象的创建由工厂来完成。就像我们去商场购买商品的时候,不需要知道商品是如何生产出来的一样,因为它由专门的公司生产。
创建模式分类:
工厂方法模式是类模式,其他四种都是对象模式
在有些系统中,为了节省内存资源、保证数据内容一致,对某些类要求只能创建一个实例,这就是单例模式。
单例模式的定义:
一个类只有一个实例,且该类能自行创建这个实例的一种模式。例如:windows系统之只能打开一个任务管理器,这样可以避免打开多个而浪费资源,或者各个窗口显示的内容不一致导致错误。
单例模式的特点:
单例模式的实现:
懒汉式单例:
该模式的特点就是类加载的时候没有生成单例,只有当第一次调用getInstance()方法的时候才会生成单例。
public class LazySingleton {
//volatile 保证instance在所有的线程中同步
private static volatile LazySingleton instance = null;
//private 避免类在外部被实例化
private LazySingleton(){
System.out.println("创建一个懒汉单例模式..");
}
// synchronized 同步操作
public static synchronized LazySingleton getInstance(){
System.out.println("模式instance="+instance);
if(null == instance){
System.out.println("开始创建..");
instance = new LazySingleton();
System.out.println("创建成功instance"+instance);
}
return instance;
}
}
public class Client {
public static void main(String[] args) {
for(int i = 0 ; i < 3 ; i++){
System.out.println(i+".================================");
LazySingleton instance = LazySingleton.getInstance();
}
}
}
运行结果:
0.================================
模式instance=null
开始创建..
创建一个懒汉单例模式..
创建成功instancecom.singleton.LazySingleton@6d06d69c
1.================================
模式instance=com.singleton.LazySingleton@6d06d69c
2.================================
模式instance=com.singleton.LazySingleton@6d06d69c
注意:如果编写多线程程序,不要删除上列代码的关键字volatile 和 synchronized ,否则会引起线程非安全问题。如果不删除这两个关键字就能保证多线程安全,但是每次访问都需要同步,会影响性能,而且消耗更多资源,这就是懒汉式单例的缺点。
饿汉单例式:该模式的特点是类一旦加载就会创建一个单例,保证在调用getInstance方法之前单例已经存在。
public class HungrySingleton {
// 类加载的时候就会创建一个单例模式
private static final HungrySingleton instance = new HungrySingleton();
// 保证实例不会被外部创建
private HungrySingleton(){
System.out.println("开始创建单例..");
}
public static HungrySingleton getInstance(){
System.out.println("获取单例..instance="+instance);
return instance;
}
}
public class Client {
public static void main(String[] args) {
for(int i = 0 ; i < 3 ; i++){
System.out.println(i+".================================");
HungrySingleton instance = HungrySingleton.getInstance();
}
}
}
运行结果:
0.================================
开始创建单例..
获取单例..instance=com.singleton.HungrySingleton@6d06d69c
1.================================
获取单例..instance=com.singleton.HungrySingleton@6d06d69c
2.================================
获取单例..instance=com.singleton.HungrySingleton@6d06d69c
饿汉式单例在类创建的时候同时也创建了一个静态对象供系统使用,以后不在改变,所以是线程安全的,可以直接用于多线程而不会出现问题。
单例模式的应用场景:
用一个已经创建好的对象作为原型,通过复制该对象原型来创建和原型相同或者相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无需知道对象创建的细节。例如:windows操作系统的安装比较繁琐,如果复制的话就简单多了。
原型模式的结构和实现
由于java提供了对象的clone()方法,所以用java的实现原型模式很简单。
//浅克隆的例子
//用原型模式生成“三好学生”奖状。
//分析:同一学校的“三好学生”奖状除了获奖人姓名不同,其他都相同,属于相似对象的复制,同样可以用原型模式创建,然后再做简单修改就可以了。
public class Citation implements Cloneable{
private String name;
private String info;
private String college;
//对象的引用
private Address address;
public Citation(String name, String info, String college) {
super();
this.name = name;
this.info = info;
this.college = college;
System.out.println("奖状创建成功 name="+name);
}
public Citation(String name, String info, String college, Address address) {
super();
this.name = name;
this.info = info;
this.college = college;
this.address = address;
System.out.println("奖状创建成功 name="+name+",address="+address.getName());
}
public void display(){
System.out.println(name+info+college+address.getName());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public String getCollege() {
return college;
}
public void setCollege(String college) {
this.college = college;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
System.out.println("奖状拷贝成功name="+name+",address="+address.getName());
return (Citation)super.clone();
}
public class Address implements Serializable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address();
address.setName("北京");
Citation citation = new Citation("张三", "这一学期成绩优异,特此颁布三好学生奖状", "北京大学",address);
citation.display();
Citation citation2 = (Citation)citation.clone();
citation2.setName("李四");
//克隆完成之后,重新设置address为shanghai,发现张三的地址也变了,也就是指向的元素地址是指向的原来张三的地址,也就是引用对象还是用的原来的地址
citation2.getAddress().setName("shanghai");
citation2.display();
citation.display();
}
}
//运行结果
奖状创建成功 name=张三,address=北京
张三这一学期成绩优异,特此颁布三好学生奖状北京大学北京
奖状拷贝成功name=张三,address=北京
李四这一学期成绩优异,特此颁布三好学生奖状北京大学shanghai
张三这一学期成绩优异,特此颁布三好学生奖状北京大学shanghai
深度克隆-:普通克隆
//普通深度克隆列子
public class Person implements Cloneable{
private String name;
private String age;
//兴趣爱好,对象的引用
private Interest interest;
//构造方法
public Person(String name, String age, Interest interest) {
super();
this.name = name;
this.age = age;
this.interest = interest;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
Person person = (Person)super.clone();
person.interest = (Interest)this.interest.clone();
return person;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public Interest getInterest() {
return interest;
}
public void setInterest(Interest interest) {
this.interest = interest;
}
public void display(){
System.out.println(name +","+age+",兴趣爱好 (instrest)"+interest.getInterest_name());
}
}
//引用对象需要实现Cloneable接口
public class Interest implements Cloneable{
private String interest_name;
public Interest(String interest_name) {
super();
this.interest_name = interest_name;
}
//引用对象内部也要重写clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
Interest interest = (Interest)super.clone();
return interest;
}
public String getInterest_name() {
return interest_name;
}
public void setInterest_name(String interest_name) {
this.interest_name = interest_name;
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Interest interest = new Interest("喝咖啡");
Person p1 = new Person("张三", "18", interest);
p1.display();
Person p2 = (Person)p1.clone();
p2.setName("李四");
p2.getInterest().setInterest_name("逛街");
p2.display();
p1.display();
}
}
//运行结果
张三,18,兴趣爱好 (instrest)喝咖啡
李四,18,兴趣爱好 (instrest)逛街
张三,18,兴趣爱好 (instrest)喝咖啡
//从运行结果中分析,李四克隆了张三的属性,但是兴趣爱好也克隆了,此时李四跟张三的兴趣指向的是不同的地址,修改李四的兴趣爱好(interset)的时候不会印象张三的兴趣爱好(interset)
深度克隆-:序列化克隆
//使用序列化克隆的时候,被克隆的类必须实现序列化接口类Serializable,否则就会出现如下错误
Exception in thread "main" java.io.NotSerializableException: com.yuanxing.Person
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at com.yuanxing.Main.main(Main.java:39)
public class Person implements Serializable{
private String name;
private String age;
//兴趣爱好,对象的引用
private Interest interest;
//构造方法
public Person(String name, String age, Interest interest) {
super();
this.name = name;
this.age = age;
this.interest = interest;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public Interest getInterest() {
return interest;
}
public void setInterest(Interest interest) {
this.interest = interest;
}
public void display(){
System.out.println(name +","+age+",兴趣爱好 (instrest)"+interest.getInterest_name());
}
}
public class Interest implements Serializable{
private String interest_name;
public Interest(String interest_name) {
super();
this.interest_name = interest_name;
}
public String getInterest_name() {
return interest_name;
}
public void setInterest_name(String interest_name) {
this.interest_name = interest_name;
}
}
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Interest interest = new Interest("打篮球");
Person p1 = new Person("张三", "18", interest);
p1.display();
//使用序列化和反序列化实现深克隆
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(p1);
byte[] bytes = out.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(in);
Person p2 = (Person)ois.readObject();
p2.getInterest().setInterest_name("看电影");
p2.setName("王麻子");
p2.display();
p1.display();
}
}
//运行结果
张三,18,兴趣爱好 (instrest)打篮球
王麻子,18,兴趣爱好 (instrest)看电影
张三,18,兴趣爱好 (instrest)打篮球
定义一个创建产品对象的工厂接口,将产品创建的实际创建工作推迟到子工厂类当中。这种模式满足典型的“创建对象与使用对象分离”的特点。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫做“简单工厂模式”,它不属于23种设计模式,缺点是增加产品时会违背“开闭原则”。
工厂模式的主要优点:
工厂模式的缺点:每增加一个产品就需要增加一个具体的产品类和具体工厂类,增加了系统的复杂度。
工厂模式的模式结构:
//例子:汽车和工厂,卡车和公共汽车都属于汽车,汽车属于抽象产品,卡车和公共汽车属于具体产品
//工厂属于抽象工厂,卡车工厂和公共汽车工厂属于具体工厂
public interface Car {
public void show();
}
public interface CarFactory {
public Car createCar();
}
public class Truck implements Car{
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("我是一辆卡车");
}
}
public class Bus implements Car{
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("我是一辆公共汽车。|-|。");
}
}
public class TruckFactory implements CarFactory{
@Override
public Car createCar() {
// TODO Auto-generated method stub
System.out.println("进入卡车工厂,开始创建卡车");
return new Truck();
}
}
public class BusFactory implements CarFactory{
@Override
public Car createCar() {
// TODO Auto-generated method stub
System.out.println("进入公共汽车工厂,开始创建公共汽车");
return new Bus();
}
}
public class Main {
public static void main(String[] args) {
Car car ;
CarFactory factory;
factory = new BusFactory();
car = factory.createCar();
car.show();
factory = new TruckFactory();
car = factory.createCar();
car.show();
}
}
//运行结果
进入公共汽车工厂,开始创建公共汽车
我是一辆公共汽车。|-|。
进入卡车工厂,开始创建卡车
我是一辆卡车
是一种访问类提供一个创建一组相关或者相互依赖对象的接口,且访问类无需指定所需要产品的具体类就能得到同族的不同等级的产品的模式结构。
抽象工厂是工厂方法模式的升级版,工厂方法只生产一个等级的产品,而抽象工厂模式可以生产多个等级的产品。
抽象工厂模式一般满足以下条件
产品登记结构与产品族
抽象工厂模式拒了具有工厂模式的特点外, 其主要有以下优点:
抽象工厂的缺点:当产品族中需要增加一个新的产品时,所有的共产类都需要进行修改。
抽象工厂模式的结构与实现
抽象工厂同工厂方法模式一样,也具有四个要素:抽象工厂、具体工厂、抽象产品、具体产品4个要素组成。但是抽象工厂中的方法个数不同,抽象产品的个数也不同。
模式的结构:
例子:每个网站都有不同的皮肤,每个皮肤包含按钮(button),输入框(textFiled),边框(comboBox)..等
//抽象产品-按钮类
public interface Button {
public void display();
}
//具体产品 - Spring按钮
public class SpringButton implements Button {
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("浅绿色Springbutton");
}
}
//具体产品 - SummerButton
public class SummerButton implements Button {
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("绿色按钮SummerButton");
}
}
//输入框
public interface TextFiled {
public void display();
}
//具体产品 - SpringTextFiled
public class SpringTextFiled implements TextFiled {
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("浅绿色textFiled");
}
}
//具体产品 - SummerTextFiled
public class SummerTextFiled implements TextFiled {
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("绿色的textFiled");
}
}
//抽象产品 - ComboBox
public interface ComboBox {
public void display();
}
//具体产品 - SpringComboBox
public class SpringComboBox implements ComboBox {
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("浅绿色Combobox");
}
}
//具体产品- SummerComboBox
public class SummerComboBox implements ComboBox {
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("绿色Combobox");
}
}
//抽象工厂
public interface SkinFactory {
public Button createButton();
public TextFiled createTextFiled();
public ComboBox createComboBox();
}
//具体工厂 - 创建SpringSkin
public class SpringSkinFactory implements SkinFactory {
@Override
public Button createButton() {
// TODO Auto-generated method stub
return new SpringButton();
}
@Override
public TextFiled createTextFiled() {
// TODO Auto-generated method stub
return new SpringTextFiled();
}
@Override
public ComboBox createComboBox() {
// TODO Auto-generated method stub
return new SpringComboBox();
}
}
//具体工厂 - 创建SummerSkin
public class SummerSkinFactory implements SkinFactory {
@Override
public Button createButton() {
// TODO Auto-generated method stub
return new SpringButton();
}
@Override
public TextFiled createTextFiled() {
// TODO Auto-generated method stub
return new SpringTextFiled();
}
@Override
public ComboBox createComboBox() {
// TODO Auto-generated method stub
return new SpringComboBox();
}
}
public class Main {
public static void main(String[] args) {
SkinFactory factory ;
Button bt;
TextFiled tf;
ComboBox cb;
//根据工厂的不同,实例化不同的具体工厂,用工厂来创建统一族的不同等级的产品
factory = new SpringSkinFactory();
bt = factory.createButton();
tf = factory.createTextFiled();
cb = factory.createComboBox();
bt.display();
tf.display();
cb.display();
}
}
//运行结果:
//浅绿色Springbutton
//浅绿色textFiled
//浅绿色Combobox
建造者模式指将一个复杂的对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。它是将一个复杂的对象分解成多个简单的对象,然后一步一步构建而成。即:产品的组成是不变的,但是每一部分都可以灵活选择。
建造者模式的优点:
建造者模式的缺点:
建造者模式跟工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法更注重零部件的创建过程,但是两者可以结合使用。
建造者模式的结构和实现
建造者模式的结构:建造者模式由产品角色、抽象建造者、具体建造者、指挥者等4个要素组成。
用建造者(Builder)模式描述客厅装修。
分析:客厅装修是一个复杂的过程,它包含墙体的装修、电视机的选择、沙发的购买与布局等。客户把装修要求告诉项目经理,项目经理指挥装修工人一步步装修,最后完成整个客厅的装修与布局,所以本实例用建造者模式实现比较适合。
这里客厅是产品,包括墙、电视和沙发等组成部分。具体装修工人是具体建造者,他们负责装修与墙、电视和沙发的布局。项目经理是指挥者,他负责指挥装修工人进行装修。
// 产品角色
public class Parlour {
private String wall;
private String tv;
private String sofa;
public void show(){
System.out.println("展示客厅的装修结果....");
System.out.println(wall);
System.out.println(tv);
System.out.println(sofa);
}
public String getWall() {
return wall;
}
public void setWall(String wall) {
this.wall = wall;
}
public String getTv() {
return tv;
}
public void setTv(String tv) {
this.tv = tv;
}
public String getSofa() {
return sofa;
}
public void setSofa(String sofa) {
this.sofa = sofa;
}
}
// 抽象的建造者
public abstract class Builder {
public Parlour parlour = new Parlour();
//构建组件
public abstract void buildWall();
//构建组件
public abstract void buildTv();
//构建组件
public abstract void buildSofa();
// 获取结果
public Parlour getResult(){
return parlour;
}
}
// 具体建造者
public class ConcreateDecoratorFirst extends Builder {
private String des = "建造者First,开始构建";
@Override
public void buildWall() {
// TODO Auto-generated method stub
System.out.println(des +"wall");
parlour.setWall("wall");
}
@Override
public void buildTv() {
// TODO Auto-generated method stub
System.out.println(des +"tv");
parlour.setTv("tv");
}
@Override
public void buildSofa() {
// TODO Auto-generated method stub
System.out.println(des +"sofa");
parlour.setSofa("sofa");
}
}
//具体建造者
public class ConcreateDecoratorSecond extends Builder {
private String des = "建造者second,开始构建";
@Override
public void buildWall() {
// TODO Auto-generated method stub
System.out.println(des +"wall");
parlour.setWall("wall");
}
@Override
public void buildTv() {
// TODO Auto-generated method stub
System.out.println(des +"tv");
parlour.setTv("tv");
}
@Override
public void buildSofa() {
// TODO Auto-generated method stub
System.out.println(des +"sofa");
parlour.setSofa("sofa");
}
}
//指挥者
public class Manager {
private Builder builder;
public Manager(Builder builder) {
this.builder = builder;
}
public Parlour decorate(){
builder.buildSofa();
builder.buildTv();
builder.buildWall();
return builder.getResult();
}
public Builder getBuilder() {
return builder;
}
public void setBuilder(Builder builder) {
this.builder = builder;
}
}
public class Main {
public static void main(String[] args) {
Builder builder = new ConcreateDecoratorFirst();
Manager manager = new Manager(builder);
Parlour parlour = manager.decorate();
parlour.show();
}
}
//运行结果:
建造者First,开始构建sofa
建造者First,开始构建tv
建造者First,开始构建wall
展示客厅的装修结果....
wall
tv
sofa
建造者模式创建的复杂对象,其产品的各个组成部分经常面领着剧烈的变化,但将他们组合在一起的算法相对稳定:
结构型模式描述如何将类或者对象按照某种布局组成更大的结构。它分为类结构模型和对象结构模型,类结构模型采用继承机制来组织接口和类,对象结构模型采用组合或聚合来组合对象。
由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构模型比类结构模型具有更大的灵活性。
结构型模式分为7种:
由于某些原因需要给对象提供一个代理以控制该对象的访问权限。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象的中介。例如:12306代售点、找工作的中介等。。
代理模式的优点:
代理模式的缺点:
代理模式的结构和实现:代理模式结构比较简单,主要是通过定义一个继承抽象主题的代理包含真实主题,从而实现对真实主题的访问。
模式结构:
例子:奔驰中国大区代理
真实主题:奔驰
代理:中国大区总代理,可以对奔驰进行加价,漏油等操作
// 抽象主题:卖车
public interface Car {
public void sell();
}
//真实主题:卖奔驰
public class BenZ implements Car{
public void sell(){
System.out.println("访问卖奔驰车的方法...");
}
}
//中国大区代理
public class CNProxy implements Car{
private BenZ benz;
@Override
public void sell() {
// TODO Auto-generated method stub
if(benz == null){
benz = new BenZ();
}
addMoney();
//利用代理类,卖奔驰
benz.sell();
afterSell();
}
//扩展
public void addMoney(){
System.out.println("加价1000$");
}
//扩展
public void afterSell(){
System.out.println("卖出去之后开始漏油...");
}
}
public class Main {
public static void main(String[] args) {
CNProxy proxy = new CNProxy();
proxy.sell();
}
}
//运行结果
先加价1000$
访问卖奔驰车的方法...
卖出去之后开始漏油...
代理模式应用场景
代理模式的扩展:SpringAOP原理其实就是用的动态代理模式。
适配器模式,将一个类的接口转换成客户希望的另一个类的接口,使得原本由于接口不兼容而不能一起工作的那些类能在一起工作。适配器模式分为类结构模式和对象结构模式两种,前者的耦合度比后者的高,且要求程序员了解现有组建中的相关的内部结构,所以应用相对较少。
适配器模式的有点:
适配器模式的缺点:
结构:
新能源汽车的发动机有电能发动机(Electric Motor)和光能发动机(Optical Motor)等,各种发动机的驱动方法不同,例如,电能发动机的驱动方法 electricDrive() 是用电能驱动,而光能发动机的驱动方法 opticalDrive() 是用光能驱动,它们是适配器模式中被访问的适配者。
客户端希望用统一的发动机驱动方法 drive() 访问这两种发动机,所以必须定义一个统一的目标接口 Motor,然后再定义电能适配器(Electric Adapter)和光能适配器(Optical Adapter)去适配这两种发动机
分析:用统一的接口去实现两种方式的切换
目标接口(统一接口):Motor
适配者:电动发动机,光力发动机
适配器:电力适配器,光力适配器
//目标接口:target
public interface Motor {
public void drive();
}
//适配者 :adaptee
public class ElectricMotor{
public void electricDrive() {
// TODO Auto-generated method stub
System.out.println("电力发动机...");
}
}
//适配者:adaptee
public class OpticalMotor {
public void opticalDrive(){
System.out.println("光力发动机发动...");
}
}
//适配器 :adapter电能适配器
public class ElectricAdapter implements Motor{
private ElectricMotor eMotor;
public ElectricAdapter(ElectricMotor eMotor) {
this.eMotor = eMotor;
}
@Override
public void drive() {
// TODO Auto-generated method stub
eMotor.electricDrive();
}
public ElectricMotor geteMotor() {
return eMotor;
}
public void seteMotor(ElectricMotor eMotor) {
this.eMotor = eMotor;
}
}
//适配器 :adapter光能适配器
public class OpticalAdapter implements Motor {
private OpticalMotor oMotor;
public OpticalAdapter(OpticalMotor oMotor) {
this.oMotor = oMotor;
}
@Override
public void drive() {
// TODO Auto-generated method stub
oMotor.opticalDrive();
}
public OpticalMotor getoMotor() {
return oMotor;
}
public void setoMotor(OpticalMotor oMotor) {
this.oMotor = oMotor;
}
}
public class Main {
public static void main(String[] args) {
System.out.println("适配器模式开始测试...");
OpticalMotor opMotor = new OpticalMotor();
Motor motor = new OpticalAdapter(opMotor);
motor.drive();
}
}
运行结果:
适配器模式开始测试...
光力发动机发动...
桥接模式:将抽象与实现分离,使他们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
桥接模式的有点:
桥接模式缺点:
可以将抽象化部分与实现化部分分开,取消二者的继承关系,改用组合关系
桥接模式的结构:
分析:女士皮包有很多种,可以按用途分、按皮质分、按品牌分、按颜色分、按大小分等,存在多个维度的变化,所以采用桥接模式来实现女士皮包的选购比较合适
颜色类:Color是一个维度,定义为实现化角色,它有两个具体实现化角色:黄色和红色,通过 getColor() 方法可以选择颜色
包类:是另一个维度,定义为抽象化角色,它有两个扩展抽象化角色:挎包和钱包,它包含了颜色类对象,通过 getName() 方法可以选择相关颜色的挎包和钱包
//实现化角色:color
public interface Color {
public String getColor();
}
//具体实现化角色:red
public class RedColor implements Color {
@Override
public String getColor() {
// TODO Auto-generated method stub
String color = "具体实现化角色:red";
return color;
}
}
//具体实现化角色:yellow
public class YellowColor implements Color {
@Override
public String getColor() {
// TODO Auto-generated method stub
String color = "具体实现化角色:yellow";
return color;
}
}
public abstract class Bag {
private Color color;
public abstract String getName();
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
}
//扩展抽象化角色:bag
public class HandBag extends Bag {
@Override
public String getName() {
// TODO Auto-generated method stub
String bag = "手包";
return bag;
}
}
//扩展抽象化角色:bag
public class WalletBag extends Bag {
@Override
public String getName() {
// TODO Auto-generated method stub
String bag = "钱包";
return bag;
}
}
public class Main {
public static void main(String[] args) {
Color color = new RedColor();
Bag bag = new HandBag();
bag.setColor(color);
System.out.println(bag.getName());
System.out.println(bag.getColor().getColor());
}
}
运行结果:
手包
具体实现化角色:red
在不改变现有对象的结构下,动态的给对象增加一些职责。例如:房子的装修,相片增加相框等。
装饰模式的有点:
装饰模式的缺点:
通常情况下,扩展一个类的功能会使用继承的方式来实现。但是继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(装饰对象)来包裹真实对象,并且保持真实对象的结构不改变的前提下,为其提供额外的功能,这就是装饰模式的目标。
模式的结构:
分析:在《恶魔战士》中,游戏角色“莫莉卡·安斯兰”的原身是一个可爱少女,但当她变身时,会变成头顶及背部延伸出蝙蝠状飞翼的女妖,当然她还可以变为穿着漂亮外衣的少女。这些都可用装饰模式来实现,在本实例中的“莫莉卡”原身有 setImage(String t) 方法决定其显示方式,而其 变身“蝙蝠状女妖”和“着装少女”可以用 setChanger() 方法来改变其外观,原身与变身后的效果用 display() 方法来
抽象构件角色:莫莉卡·安斯兰
具体构件角色:原身
抽象装饰角色:变形
具体装饰角色:女妖
//抽象构件角色:morrigan
public interface Morrigan {
public void display();
}
//具体装饰角色:原身
public class Original implements Morrigan{
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("莫丽卡原身...");
}
public Original() {
System.out.println("莫丽卡初始化原身...");
}
}
// 抽象装饰角色:change
public class Change implements Morrigan{
private Morrigan morrigan;
@Override
public void display() {
// TODO Auto-generated method stub
morrigan.display();
}
public Change(Morrigan morrigan) {
this.morrigan = morrigan;
}
public Morrigan getMorrigan() {
return morrigan;
}
public void setMorrigan(Morrigan morrigan) {
this.morrigan = morrigan;
}
}
public class Girl extends Change{
public Girl(Morrigan morrigan) {
super(morrigan);
}
@Override
public void display() {
// TODO Auto-generated method stub
super.display();
setChange();
}
//为具体的构建添加一些责任
public void setChange(){
System.out.println("你是一个漂亮的美女");
}
}
public class Main {
public static void main(String[] args) {
Morrigan morrigan = new Original();
morrigan.display();
System.out.println("--------开始进行装饰------------");
Change change = new Girl(morrigan);
change.display();
}
}
运行结果:
莫丽卡初始化原身...
莫丽卡原身...
--------开始进行装饰------------
莫丽卡原身...
你是一个漂亮的美女
装饰模式应用场景:
装饰模式在java源码中体现在:InputStream 的子类 FilterInputStream,OutputStream 的子类 FilterOutputStream,Reader 的子类 BufferedReader 以及 FilterReader,还有 Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等,它们都是抽象装饰类。
是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一的接口,外部应用程序不需要关心子系统是怎么实现的,这样大大降低了应用程序的复杂性,提高了应用程序的可维护性。(其实就是模块定义的接口facade,系统之间相互调用的时候用的)
外观模式的优点:
外观模式的缺点:
外观模式结构比较简单,主要定义了一个高层的接口。它包含了对各个子系统的引用,客户端可以通过它访问各个子系统的功能。
外观模式的结构:
//抽象外观角色 - 为了不违背开闭原则,增加抽象外观角色
public abstract class AbstractFacade {
public abstract void method1();
public abstract void method2();
}
// 具体外观角色
public class Facade1 extends AbstractFacade {
private System01 system01 = new System01();
private System02 system02 = new System02();
private System03 system03 = new System03();
@Override
public void method1() {
// TODO Auto-generated method stub
system01.run();
system02.run();
}
@Override
public void method2() {
// TODO Auto-generated method stub
system02.run();
system03.run();
}
}
// 具体外观角色
public class Facade2 extends AbstractFacade {
private System01 system01 = new System01();
private System02 system02 = new System02();
private System03 system03 = new System03();
@Override
public void method1() {
// TODO Auto-generated method stub
system01.run();
system02.run();
system03.run();
}
@Override
public void method2() {
// TODO Auto-generated method stub
system03.run();
}
}
// 子系统 01
public class System01 {
public void run(){
System.out.println("子系统_01被调用...");
}
}
//子系统 02
public class System02 {
public void run(){
System.out.println("子系统_02被调用...");
}
}
//子系统 03
public class System03 {
public void run(){
System.out.println("子系统_03被调用...");
}
}
public class Main {
public static void main(String[] args) {
AbstractFacade facade = new Facade2();
facade.method1();
}
}
运行结果:
子系统_01被调用...
子系统_02被调用...
子系统_03被调用...
通常情况下如下几种情况可以使用外观模式:
运用共享技术有效的支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。
享元模式的优点:相同的对象只需要保存一份,降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。
享元模式的缺点:
享元模式中存在两种状态:
享元模式的结构:
//抽象享元角色 - 建筑
public interface JianZhu {
public void use();
}
//具体享元角色 - 体育场
public class TiYuGuan implements JianZhu{
private String name;
private String shape;
private String yundong;
public TiYuGuan(String yundong) {
super();
this.yundong = yundong;
}
@Override
public void use() {
// TODO Auto-generated method stub
System.out.println("体育馆被使用来召开运动:("+yundong +")体育场形状为:("+shape+")运动名称为("+name+")");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getShape() {
return shape;
}
public void setShape(String shape) {
this.shape = shape;
}
public String getYundong() {
return yundong;
}
public void setYundong(String yundong) {
this.yundong = yundong;
}
}
//角色工厂
public class JianZhuFactory {
private static final Map factory = new HashMap();
public static TiYuGuan getTyg(String yundong){
TiYuGuan tyg = factory.get(yundong);
if(null == tyg){
tyg = new TiYuGuan(yundong);
factory.put(yundong, tyg);
}
return tyg;
}
public static int getSize(){
return factory.size();
}
}
public class Main {
public static void main(String[] args) {
JianZhuFactory factory = new JianZhuFactory();
for(int i = 0 ; i < 10 ; i++){
//自始至终总共有10个数据,但是只创建了一个共享对象
TiYuGuan tiyuguan = factory.getTyg("足球");
tiyuguan.setName("中国体育馆");
tiyuguan.setShape("圆形");
tiyuguan.use();
System.out.println(factory.getSize());
}
}
}
运行结果:
体育馆被使用来召开运动:(足球)体育场形状为:(圆形)运动名称为(中国体育馆)
1
体育馆被使用来召开运动:(足球)体育场形状为:(圆形)运动名称为(中国体育馆)
1
体育馆被使用来召开运动:(足球)体育场形状为:(圆形)运动名称为(中国体育馆)
1
体育馆被使用来召开运动:(足球)体育场形状为:(圆形)运动名称为(中国体育馆)
1
体育馆被使用来召开运动:(足球)体育场形状为:(圆形)运动名称为(中国体育馆)
1
体育馆被使用来召开运动:(足球)体育场形状为:(圆形)运动名称为(中国体育馆)
1
体育馆被使用来召开运动:(足球)体育场形状为:(圆形)运动名称为(中国体育馆)
1
体育馆被使用来召开运动:(足球)体育场形状为:(圆形)运动名称为(中国体育馆)
1
体育馆被使用来召开运动:(足球)体育场形状为:(圆形)运动名称为(中国体育馆)
1
体育馆被使用来召开运动:(足球)体育场形状为:(圆形)运动名称为(中国体育馆)
1
组合模式有时又叫做部分-整体模式,它是一种对象组合成树状的层次结构模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性。
组合模式的优点:
组合模式的缺点:
组合模式主要包含以下结构:
组合模式分为透明式的组合模式和安全式的组合模式
//透明式组合模式
//抽象构件角色
public interface Compent {
public void add(Compent c);
public void remove(Compent c);
public Compent getChild(int i);
public void operation();
}
// 树枝组建角色
public class Branch implements Compent{
private List children = new ArrayList();
@Override
public void add(Compent c) {
// TODO Auto-generated method stub
children.add(c);
}
@Override
public void remove(Compent c) {
// TODO Auto-generated method stub
children.remove(c);
}
@Override
public Compent getChild(int i) {
// TODO Auto-generated method stub
return children.get(i);
}
@Override
public void operation() {
// TODO Auto-generated method stub
for(Compent o : children){
o.operation();
}
}
}
public class Leaf implements Compent{
private String name;
@Override
public void add(Compent c) {
// TODO Auto-generated method stub
}
@Override
public void remove(Compent c) {
// TODO Auto-generated method stub
}
@Override
public Compent getChild(int i) {
// TODO Auto-generated method stub
return null;
}
@Override
public void operation() {
// TODO Auto-generated method stub
System.out.println("树叶"+name+":被访问!");
}
public Leaf(String name) {
super();
this.name = name;
}
}
运行结果:
树叶leaf1:被访问!
树叶leaf3:被访问!
树叶leaf2:被访问!
说明:假如李先生到韶关“天街e角”生活用品店购物,用 1 个红色小袋子装了 2 包婺源特产(单价 7.9 元)、1 张婺源地图(单价 9.9 元);用 1 个白色小袋子装了 2 包韶关香藉(单价 68 元)和 3 包韶关红茶(单价 180 元);用 1 个中袋子装了前面的红色小袋子和 1 个景德镇瓷器(单价 380 元);用 1 个大袋子装了前面的中袋子、白色小袋子和 1 双李宁牌运动鞋(单价 198 元)。
最后“大袋子”中的内容有:{1 双李宁牌运动鞋(单价 198 元)、白色小袋子{2 包韶关香菇(单价 68 元)、3 包韶关红茶(单价 180 元)}、中袋子{1 个景德镇瓷器(单价 380 元)、红色小袋子{2 包婺源特产(单价 7.9 元)、1 张婺源地图(单价 9.9 元)}}},现在要求编程显示李先生放在大袋子中的所有商品信息并计算要支付的总价。
// 袋子 - 抽象类角色
public interface Bag {
public void add(Bag bag);
public void remove(Bag bag);
public Bag getChild(int i);
public void operation();
public int calculation();
}
//树枝角色
public class BagBranch implements Bag{
private List childs = new ArrayList();
private String name;
@Override
public void add(Bag bag) {
// TODO Auto-generated method stub
childs.add(bag);
}
@Override
public void remove(Bag bag) {
// TODO Auto-generated method stub
childs.remove(bag);
}
@Override
public Bag getChild(int i) {
// TODO Auto-generated method stub
return childs.get(i);
}
@Override
public void operation() {
// TODO Auto-generated method stub
for(Bag bag : childs){
bag.operation();
}
}
@Override
public int calculation() {
// TODO Auto-generated method stub
int s = 0;
for(Bag bag : childs){
s += bag.calculation();
}
return s;
}
public BagBranch(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//树叶角色
public class BagDetail implements Bag{
private String name ;
private int price;
private int num;
@Override
public void add(Bag bag) {
// TODO Auto-generated method stub
}
@Override
public void remove(Bag bag) {
// TODO Auto-generated method stub
}
@Override
public Bag getChild(int i) {
// TODO Auto-generated method stub
return null;
}
@Override
public void operation() {
// TODO Auto-generated method stub
System.out.println("商品名称:("+name+"),数量:("+num+"),单价:("+price+")元,总价="+(this.calculation())+"元");
}
@Override
public int calculation() {
// TODO Auto-generated method stub
return num * price;
}
public BagDetail(String name, int price, int num) {
super();
this.name = name;
this.price = price;
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
public class Main {
public static void main(String[] args) {
Bag bag = new BagBranch("大袋子");
Bag middleBag = new BagBranch("中袋子");
Bag redBag = new BagBranch("红袋子");
Bag te = new BagDetail("特产", 8, 2);
Bag map = new BagDetail("地图", 10, 1);
redBag.add(te);
redBag.add(map);
middleBag.add(redBag);
Bag shoses = new BagDetail("李宁鞋", 168, 1);
Bag whiteBag = new BagBranch("白袋子");
Bag xiang = new BagDetail("香记", 68, 2);
Bag tea = new BagDetail("红茶", 180, 3);
whiteBag.add(xiang);
whiteBag.add(tea);
bag.add(middleBag);
bag.add(shoses);
bag.add(whiteBag);
bag.operation();
int all = bag.calculation();
System.out.println("总价"+all);
}
}
运行结果:
商品名称:(特产),数量:(2),单价:(8)元,总价=16元
商品名称:(地图),数量:(1),单价:(10)元,总价=10元
商品名称:(李宁鞋),数量:(1),单价:(168)元,总价=168元
商品名称:(香记),数量:(2),单价:(68)元,总价=136元
商品名称:(红茶),数量:(3),单价:(180)元,总价=540元
总价870
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间相互协作共同完成的单个对象都无法完成的任务,它涉及算法及对象间责任的分配。
行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或者聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。
模板方法的模式定义,定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中操作,使得子类在不改变该算法的结构情况下重定义该算法的某些特定的步骤。它是一种类行为模式。
模板方法的主要优点:
模板方法的缺点:
模板方法模式需要注意抽象类与具体类之间的协作,用到了虚函数的多态性技术以及“不用调用我,让我来调用你”的方向控制技术。
抽象类:负责给出一个算法的骨架和轮廓,它由一个模板方法和若干基本方法组成。
具体子类:实现抽象类中所有定义的抽象方法和钩子方法,他们是一个顶级逻辑的一个组成步骤。
出国留学:
国留学手续一般经过以下流程:
索取学校资料,
提出入学申请,
办理因私出国护照,出境卡和公证,
申请签证,
体检,
订机票,
准备行装,
抵达目标学校等,
其中有些业务对各个学校是一样的,但有些业务因学校不同而不同,所以比较适合用模板方法模式来实现。
在本实例中,我们先定义一个出国留学的抽象类 StudyAbroad,里面包含了一个模板方法 TemplateMethod(),该方法中包含了办理出国留学手续流程中的各个基本方法,其中有些方法的处理由于各国都一样,所以在抽象类中就可以实现,但有些方法的处理各国是不同的,必须在其具体子类(如美国留学类 StudyInAmerica)中实现。如果再增加一个国家,只要增加一个子类就可以了
//出国留学 - 抽象类
public abstract class StudyAboard {
//模范方法
public void templateMethod(){
lookingForSchool(); //1.获取学校资料-抽象方法
applyForEnrol();//2.提出入学申请-抽象方法
applayForPassport();//3.办理因私申请护照,出境卡和公证-基本方法
applyForVisa();//4.申请签证-基本方法
readyGoAbroad();//5.体检、订机票、准备行装-基本方法
arriving();//6.抵达-抽象方法
}
//1.获取学校资料-抽象方法
public abstract void lookingForSchool();
//2.提出入学申请-抽象方法
public abstract void applyForEnrol();
//3.办理因私申请护照,出境卡和公证-基本方法
public void applayForPassport(){
System.out.println("三.办理因私出国护照、出境卡和公证:");
System.out.println(" 1)持录取通知书、本人户口簿或身份证向户口所在地公安机关申请办理因私出国护照和出境卡。");
System.out.println(" 2)办理出生公证书,学历、学位和成绩公证,经历证书,亲属关系公证,经济担保公证。");
}
//4.申请签证-基本方法
public void applyForVisa(){
System.out.println("四.申请签证:");
System.out.println(" 1)准备申请国外境签证所需的各种资料,包括个人学历、成绩单、工作经历的证明;个人及家庭收入、资金和财产证明;家庭成员的关系证明等;");
System.out.println(" 2)向拟留学国家驻华使(领)馆申请入境签证。申请时需按要求填写有关表格,递交必需的证明材料,缴纳签证。有的国家(比如美国、英国、加拿大等)在申请签证时会要求申请人前往使(领)馆进行面试。");
}
//5.体检、订机票、准备行装-基本方法
public void readyGoAbroad(){
System.out.println("五.体检、订机票、准备行装:");
System.out.println(" 1)进行身体检查、免疫检查和接种传染病疫苗;");
System.out.println(" 2)确定机票时间、航班和转机地点。");
}
//6.抵达-抽象方法
public abstract void arriving();
}
public class StudyAmerica extends StudyAboard{
@Override
public void lookingForSchool() {
// TODO Auto-generated method stub
System.out.println("一.索取学校以下资料:");
System.out.println(" 1)对留学意向国家的政治、经济、文化背景和教育体制、学术水平进行较为全面的了解;");
System.out.println(" 2)全面了解和掌握国外学校的情况,包括历史、学费、学制、专业、师资配备、教学设施、学术地位、学生人数等;");
System.out.println(" 3)了解该学校的住宿、交通、医疗保险情况如何;");
System.out.println(" 4)该学校在中国是否有授权代理招生的留学中介公司?");
System.out.println(" 5)掌握留学签证情况;");
System.out.println(" 6)该国政府是否允许留学生合法打工?");
System.out.println(" 8)毕业之后可否移民?");
System.out.println(" 9)文凭是否受到我国认可?");
}
@Override
public void applyForEnrol() {
// TODO Auto-generated method stub
System.out.println("二.入学申请:");
System.out.println(" 1)填写报名表;");
System.out.println(" 2)将报名表、个人学历证明、最近的学习成绩单、推荐信、个人简历、托福或雅思语言考试成绩单等资料寄往所申请的学校;");
System.out.println(" 3)为了给签证办理留有充裕的时间,建议越早申请越好,一般提前1年就比较从容。");
}
@Override
public void arriving() {
// TODO Auto-generated method stub
System.out.println("六.抵达目标学校:");
System.out.println(" 1)安排住宿;");
System.out.println(" 2)了解校园及周边环境。");
}
}
public class Main {
public static void main(String[] args) {
StudyAboard studyAboard = new StudyAmerica();
studyAboard.templateMethod();
}
}
运行结果:
一.索取学校以下资料:
1)对留学意向国家的政治、经济、文化背景和教育体制、学术水平进行较为全面的了解;
2)全面了解和掌握国外学校的情况,包括历史、学费、学制、专业、师资配备、教学设施、学术地位、学生人数等;
3)了解该学校的住宿、交通、医疗保险情况如何;
4)该学校在中国是否有授权代理招生的留学中介公司?
5)掌握留学签证情况;
6)该国政府是否允许留学生合法打工?
8)毕业之后可否移民?
9)文凭是否受到我国认可?
二.入学申请:
1)填写报名表;
2)将报名表、个人学历证明、最近的学习成绩单、推荐信、个人简历、托福或雅思语言考试成绩单等资料寄往所申请的学校;
3)为了给签证办理留有充裕的时间,建议越早申请越好,一般提前1年就比较从容。
三.办理因私出国护照、出境卡和公证:
1)持录取通知书、本人户口簿或身份证向户口所在地公安机关申请办理因私出国护照和出境卡。
2)办理出生公证书,学历、学位和成绩公证,经历证书,亲属关系公证,经济担保公证。
四.申请签证:
1)准备申请国外境签证所需的各种资料,包括个人学历、成绩单、工作经历的证明;个人及家庭收入、资金和财产证明;家庭成员的关系证明等;
2)向拟留学国家驻华使(领)馆申请入境签证。申请时需按要求填写有关表格,递交必需的证明材料,缴纳签证。有的国家(比如美国、英国、加拿大等)在申请签证时会要求申请人前往使(领)馆进行面试。
五.体检、订机票、准备行装:
1)进行身体检查、免疫检查和接种传染病疫苗;
2)确定机票时间、航班和转机地点。
六.抵达目标学校:
1)安排住宿;
2)了解校园及周边环境。
该模式定义一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的的变化不会影响使用他们的客户。策略模式属于对象行为模式,通过对算法的封装,把使用算法的责任和算法的实现分割开来,并威派格不同的对象对这些算法进行管理。
优点:
缺点:
策略模式是准备一组算法,并将这组算法封装到一系列的策略类里面,作为一个抽象策略类的子类,策略模式的重心不是如何实现算法,而是如何组织这些算法,从而让程序结构更加灵活,具有更好的维护性和扩展性。
// 抽象类 - 抽象策略类
public interface Strategy {
//策略方法
public void strategyMethod();
}
//具体策略类- A
public class JuTiStrategyA implements A{
@Override
public void strategyMethod() {
// TODO Auto-generated method stub
System.out.println("具体策略A的策略方法被访问!");
}
}
public class JuTiStrategyB implements B{
@Override
public void strategyMethod() {
// TODO Auto-generated method stub
System.out.println("具体策略B的策略方法被访问!");
}
}
public class Main {
public static void main(String[] args) {
Strategy strategy = new JuTiStrategyA();
Context context = new Context();
context.setStrategy(strategy);
context.strategyMethod();
Strategy b = new JuTiStrategyB();
context.setStrategy(b);
context.strategyMethod();
}
}
运行结果:
具体策略A的策略方法被访问!
具体策略B的策略方法被访问!
将一个请求封装成一个对象,使发出请求的责任和执行请求的责任分开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。
// 抽象命令角色:声明执行命令的接口
public interface Command {
//拥有执行命令的抽象方法execute();
public void execute();
}
// 接收者:执行命令的功能相关操作,是具体命令对象业务的真正实现
public class ReceiverA {
//实现命令
public void action(){
System.out.println("接收命令A");
}
}
// 接收者:执行命令的功能相关操作,是具体命令对象业务的真正实现
public class ReceiverB {
//实现命令
public void action(){
System.out.println("接收命令B");
}
}
// 具体命令类角色:实现抽象命令类,
public class JuTiCommandA implements Command{
private ReceiverA receiverA;
@Override
public void execute() {
// TODO Auto-generated method stub
receiverA.action();
}
public ReceiverA getReceiverA() {
return receiverA;
}
public void setReceiverA(ReceiverA receiverA) {
this.receiverA = receiverA;
}
public JuTiCommandA() {
this.receiverA = new ReceiverA();
}
}
// 具体命令类角色:实现抽象命令类,
public class JuTiCommandB implements Command{
private ReceiverB receiverB;
@Override
public void execute() {
// TODO Auto-generated method stub
receiverB.action();
}
public ReceiverB getReceiverB() {
return receiverB;
}
public void setReceiverB(ReceiverB receiverB) {
this.receiverB = receiverB;
}
public JuTiCommandB() {
this.receiverB = new ReceiverB();
}
}
// 调用者角色:是请求的发送者,通常用友很多的命令对象,并通过访问命令对象来执行相关请求,不直接访问接收者
public class Invoker {
private Command command;
public void cell(){
command.execute();
}
public Command getCommand() {
return command;
}
public void setCommand(Command command) {
this.command = command;
}
public Invoker(Command command) {
super();
this.command = command;
}
}
public class Main {
public static void main(String[] args) {
Invoker invoker = null;
Command command = new JuTiCommandA();
invoker = new Invoker(command);
invoker.cell();
Command command2 = new JuTiCommandB();
invoker = new Invoker(command2);
invoker.cell();
}
}
运行结果:
接收命令A
接收命令B
【例1】用命令模式实现客户去餐馆吃早餐的实例。
分析:客户去餐馆可选择的早餐有肠粉、河粉和馄饨等,客户可向服务员选择以上早餐中的若干种,服务员将客户的请求交给相关的厨师去做。这里的点早餐相当于“命令”,服务员相当于“调用者”,厨师相当于“接收者”,所以用命令模式实现比较合适。
首先,定义一个早餐类(Breakfast),它是抽象命令类,有抽象方法 cooking(),说明要做什么;再定义其子类肠粉类(ChangFen)、馄饨类(HunTun)和河粉类(HeFen),它们是具体命令类,实现早餐类的 cooking() 方法,但它们不会具体做,而是交给具体的厨师去做;具体厨师类有肠粉厨师(ChangFenChef)、馄蚀厨师(HunTunChef)和河粉厨师(HeFenChef),他们是命令的接收者,
// 抽象命令类
public interface BreakFast {
public abstract void cooking();
}
//接收者 - 服务员
public class ChangFenChef{
public void diancan(){
System.out.println("点一份河粉");
}
}
//接收者
public class HeFenChef{
public void diancan(){
System.out.println("点一份河粉");
}
}
//接收者
public class HunTunChef{
public void diancan(){
System.out.println("点一份馄饨");
}
}
//具体实现者 - 厨师
public class HeFen implements BreakFast{
private HeFenChef HeFenChef;
@Override
public void cooking() {
// TODO Auto-generated method stub
HeFenChef.diancan();
}
public HeFenChef getHeFenChef() {
return HeFenChef;
}
public void setHeFenChef(HeFenChef heFenChef) {
HeFenChef = heFenChef;
}
public HeFen() {
this.HeFenChef = new HeFenChef();
}
}
//具体实现者
public class HunTun implements BreakFast{
private HunTunChef HunTunChef;
@Override
public void cooking() {
// TODO Auto-generated method stub
HunTunChef.diancan();
}
public HunTunChef getHunTunChef() {
return HunTunChef;
}
public void setHunTunChef(HunTunChef hunTunChef) {
HunTunChef = hunTunChef;
}
public HunTun() {
this.HunTunChef = new HunTunChef();
}
}
//具体实现者
public class ChangFen implements BreakFast{
private ChangFenChef ChangFenChef;
@Override
public void cooking() {
// TODO Auto-generated method stub
ChangFenChef.diancan();
}
public ChangFenChef getChangFenChef() {
return ChangFenChef;
}
public void setChangFenChef(ChangFenChef changFenChef) {
ChangFenChef = changFenChef;
}
public ChangFen() {
this.ChangFenChef = new ChangFenChef();
}
}
// 调用者 - 顾客
public class Invoker {
private BreakFast breakFast;
public void diancan(){
breakFast.cooking();
}
public BreakFast getBreakFast() {
return breakFast;
}
public void setBreakFast(BreakFast breakFast) {
this.breakFast = breakFast;
}
public Invoker(BreakFast breakFast) {
super();
this.breakFast = breakFast;
}
}
public class Main {
public static void main(String[] args) {
Invoker invoker = null;
BreakFast breakFast = null;
breakFast = new HeFen();
invoker = new Invoker(breakFast);
invoker.diancan();
breakFast = new ChangFen();
invoker = new Invoker(breakFast);
invoker.diancan();
breakFast = new HunTun();
invoker = new Invoker(breakFast);
invoker.diancan();
}
}
运行结果:
点一份河粉
点一份河粉
点一份馄饨
定义:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连城一条链;当有请求发生时,可将请求沿着这条链传递,知道有对象处理它为止。
在责任链模式中,客户只需要将请求发送到责任链上即可,无需关心请求的处理细节和请求的传递过程,所以责任链将请求的发送者和请求的处理者解耦了。
优点:
缺点:
// 抽象处理角色 -
public abstract class Handler {
private Handler next;
public abstract void handleRequest(String request);
public Handler getNext() {
return next;
}
public void setNext(Handler next) {
this.next = next;
}
}
//具体处理角色
public class JuTiHandlerA extends Handler{
@Override
public void handleRequest(String request) {
// TODO Auto-generated method stub
if(request.equals("one")){
System.out.println(request +"具体处理者 A");
}else{
if(getNext() != null){
getNext().handleRequest(request);
}else{
System.out.println("没有处理该请求");
}
}
}
}
//具体处理角色
public class JuTiHandlerB extends Handler{
@Override
public void handleRequest(String request) {
// TODO Auto-generated method stub
if(request.equals("two")){
System.out.println(request +"具体处理者 B");
}else{
if(getNext() != null){
getNext().handleRequest(request);
}else{
System.out.println("没有处理该请求");
}
}
}
}
public class Main {
public static void main(String[] args) {
Handler handler = new JuTiHandlerA();
Handler handler2 = new JuTiHandlerB();
handler.setNext(handler2);
handler.handleRequest("one");
}
}
运行结果:
one具体处理者 A
对有状态的对象,把复杂的“判断逻辑(if-else)”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
优点:
缺点:
状态模式将把受环境改变的对象行为包装在不同的状态对象里,其意图是让一个对象在其内部状态改变的时候,其行为也随之改变。
结构:
//抽象角色
public abstract class Stat {
public abstract void Handle(Context context);
}
// 环境角色
public class Context {
private Stat stat;
public void Handle(){
stat.Handle(this);
}
public Context() {
stat = new JuTiStat1();
}
public Stat getStat() {
return stat;
}
public void setStat(Stat stat) {
this.stat = stat;
}
}
//具体状态角色
public class JuTiStat1 extends Stat{
@Override
public void Handle(Context context) {
// TODO Auto-generated method stub
System.out.println("状态 ..... A");
context.setStat(new JuTiStat2());
}
}
//具体状态角色
public class JuTiStat2 extends Stat{
@Override
public void Handle(Context context) {
// TODO Auto-generated method stub
System.out.println("状态 ..... B");
context.setStat(new JuTiStat1());
}
}
public class Main {
public static void main(String[] args) {
Context context = new Context();
context.Handle();
context.Handle();
context.Handle();
context.Handle();
}
}
运行结果:
状态 ..... A
状态 ..... B
状态 ..... A
状态 ..... B
海贼王中路飞在打多弗朗明哥的时候,首先是普通状态,然后发怒开启二挡状态,被多弗朗明哥嘲笑速度快,但是力量低,于是开启三挡状态,又被嘲笑力量够了,但是速度差远了,路飞被逼急,于是开启四挡,最终打败了多弗朗明哥。现在我们通过代码实现这样的一个过程。
//抽象角色 - 路飞的状态
public interface LuFeiState {
public void change();
}
//具体角色
class Ordinary implements LuFeiState{
@Override
public void change() {
System.out.println("路飞当前为普通状态战斗");
}
}
class SecondGear implements LuFeiState{
@Override
public void change() {
System.out.println("路飞开启三挡战斗");
}
}
class ThirdGear implements LuFeiState{
@Override
public void change() {
System.out.println("路飞开启三挡战斗");
}
}
class FourthGear implements LuFeiState{
@Override
public void change() {
System.out.println("路飞开启四挡战斗");
}
}
public class LuFei {
public final static int ORDINARY = 0;//普通状态
public final static int SECONDGEAR = 1;//二挡状态
public final static int THIRDGEAR = 2;//三挡状态
public final static int FOURTHGEAR = 3;//四挡状态
private LuFeiState state = new Ordinary();//由于路飞一开始是普通状态,所以我们初始化state为ORDINARY
public LuFeiState getState() {
return state;
}
public void setState(LuFeiState state) {
this.state = state;
}
public void change(){
state.change();
}
}
public class Main {
public static void main(String[] args) {
LuFei luFei = new LuFei();
luFei.setState(new SecondGear());
luFei.change();
luFei.setState(new ThirdGear());
luFei.change();
luFei.setState(new FourthGear());
luFei.change();
luFei.setState(new Ordinary());
luFei.change();
}
}
运行结果:
路飞开启三挡战斗
路飞开启三挡战斗
路飞开启四挡战斗
路飞当前为普通状态战斗
定义:多个对象存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并被自动更新,这种模式有时又称作发布-订阅模式,模型-视图模式,它是对象行为模式。
优点:
缺点:
实现观察者模式的时候需要注意目标对象和具体对象之间不能直接调用,否则使两者之间紧密耦合起来,这违反了面向对象的设计原则。
结构:
【例1】利用观察者模式设计一个程序,分析“人民币汇率”的升值或贬值对进口公司的进口产品成本或出口公司的出口产品收入以及公司的利润率的影响。
分析:当“人民币汇率”升值时,进口公司的进口产品成本降低且利润率提升,出口公司的出口产品收入降低且利润率降低;当“人民币汇率”贬值时,进口公司的进口产品成本提升且利润率降低,
出口公司的出口产品收入提升且利润率提升。
这里的汇率(Rate)类是抽象目标类,它包含了保存观察者(Company)的 List 和增加/删除观察者的方法,以及有关汇率改变的抽象方法 change(int number);而人民币汇率(RMBrate)类是具体目标,
它实现了父类的 change(int number) 方法,即当人民币汇率发生改变时通过相关公司;公司(Company)类是抽象观察者,它定义了一个有关汇率反应的抽象方法 response(int number);
进口公司(ImportCompany)类和出口公司(ExportCompany)类是具体观察者类,它们实现了父类的 response(int number) 方法,即当它们接收到汇率发生改变的通知时作为相应的反应
// 抽象目标类角色
public abstract class Rate {
List companys = new ArrayList();
public void add(Company company){
companys.add(company);
}
public void remove(Company company){
companys.remove(company);
}
//抽象通知接口
public abstract void change(int num);
}
//抽象观察者接口
public abstract class Company {
//抽象接口,更新自己状态
public abstract void response(int num);
}
//具体抽象目标接口
public class RMBRate extends Rate {
//,实现抽象接口,通知所有注册过的观察者
@Override
public void change(int num) {
// TODO Auto-generated method stub
for(Company company : companys){
company.response(num);
}
}
}
//具体观察者
public class ImportCompany extends Company {
@Override
public void response(int num) {
// TODO Auto-generated method stub
if(num > 0){
System.out.println("人民币汇率升值"+num+"个基点,降低了进口产品成本,提升了进口公司利润率。");
}else{
System.out.println("人民币汇率贬值"+(-num)+"个基点,提升了进口产品成本,降低了进口公司利润率。");
}
}
}
//具体观察者
public class ExportCompany extends Company {
@Override
public void response(int num) {
// TODO Auto-generated method stub
if(num>0){
System.out.println("人民币汇率升值"+num+"个基点,降低了出口产品收入,降低了出口公司的销售利润率。");
}else if(num<0){
System.out.println("人民币汇率贬值"+(-num)+"个基点,提升了出口产品收入,提升了出口公司的销售利润率。");
}
}
}
public class Main {
public static void main(String[] args) {
Rate rate = new RMBRate();
rate.add(new ImportCompany());
rate.add(new ExportCompany());
rate.change(1);
rate.change(-10);
}
}
运行结果:
人民币汇率升值1个基点,降低了进口产品成本,提升了进口公司利润率。
人民币汇率升值1个基点,降低了出口产品收入,降低了出口公司的销售利润率。
人民币汇率贬值10个基点,提升了进口产品成本,降低了进口公司利润率。
人民币汇率贬值10个基点,提升了出口产品收入,提升了出口公司的销售利润率。
定义:定义一个中介者对象来封装一系列的对象之间的交互,使原有对象之间耦合松散,可以独立的改变他们之间得交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。
优点:
缺点:
中介者模式实现的关键是找出“中介者”。
结构:
// 抽象中介者角色
public abstract class Medium {
public abstract void regist(Customer customer);
public abstract void relay(String from,String msg);
}
public abstract class Customer {
protected Medium medium;
private String name;
public abstract void send(String msg);
public abstract void recive(String from ,String msg);
public Medium getMedium() {
return medium;
}
public void setMedium(Medium medium) {
this.medium = medium;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class EstateMedium extends Medium {
private List customers = new ArrayList();
@Override
public void regist(Customer customer) {
// TODO Auto-generated method stub
if(!customers.contains(customer)){
customers.add(customer);
customer.setMedium(this);
}
}
@Override
public void relay(String from, String msg) {
// TODO Auto-generated method stub
for(Customer customer : customers){
String name = customer.getName();
if(!name.equals(from)){
customer.recive(from,msg);
}
}
}
}
public class Seller extends Customer{
@Override
public void send(String msg) {
// TODO Auto-generated method stub
System.out.println("我(卖方)说:"+msg);
}
@Override
public void recive(String from ,String msg) {
// TODO Auto-generated method stub
System.out.println(from +"说:"+msg);
}
}
public class Buyer extends Customer{
@Override
public void send(String msg) {
// TODO Auto-generated method stub
System.out.println("我(买方)说:"+msg);
}
@Override
public void recive(String from ,String msg) {
// TODO Auto-generated method stub
System.out.println(from +"说:"+msg);
}
}
public class Main {
public static void main(String[] args) {
Medium medium = new EstateMedium();
Customer seller = new Seller();
Customer buyer = new Buyer();
medium.regist(seller);
medium.regist(buyer);
seller.send("你好");
buyer.send("你好");
seller.recive("seller", "哈哈");
buyer.recive("buyer", "么么哒");
}
}
运行结果:
我(卖方)说:你好
我(买方)说:你好
seller说:哈哈
buyer说:么么哒
定义:提供一个对象来顺序访问集合对象中的一系列数据,而不暴露集合内部对象的表示,迭代器模式是一种对象行为模式
优点:
缺点:
迭代器模式是通过将聚合类的对象遍历行为分离出来,抽象成迭代器类来实现,其目的是在不暴露聚合对象的内部结构下,让外部代码透明的访问聚合的内部数据。
结构:
// 抽象聚合角色
public abstract class Aggregate {
public abstract void add(Object obj);
public abstract void remove(Object obj);
public abstract Iterator getIterator();
}
// 具体聚合角色
public class ConcreteAggregate extends Aggregate {
List
运行结果:
啦啦啦
么么哒
哈哈哈
first:啦啦啦
定义:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可添加这些元素的新操作,为数据结构中每个元素提供多种访问方式。它将对数据的操作和数据的结构进行分离,是行为类模式中最复杂的一种。
优点:
缺点:
访问者模式实现的关键是如何将作用于元素的操作分离出来封装成独立的类
// 抽象访问者角色
public abstract class Visitor {
public abstract void visit(ElementA a );
public abstract void visit(ElementB b );
}
// 抽象元素角色
public abstract class Element {
public abstract void accept(Visitor visitor);
}
public class ElementA extends Element{
@Override
public void accept(Visitor visitor) {
// TODO Auto-generated method stub
visitor.visit(this);
}
public String operationA(){
return "具体元素A";
}
}
public class ElementB extends Element{
@Override
public void accept(Visitor visitor) {
// TODO Auto-generated method stub
visitor.visit(this);
}
public String operationB(){
return "具体元素B";
}
}
public class VisitorA extends Visitor{
@Override
public void visit(ElementA a) {
// TODO Auto-generated method stub
System.out.println("具体访问者A ->"+a.operationA());
}
@Override
public void visit(ElementB b) {
// TODO Auto-generated method stub
System.out.println("具体访问者A ->"+b.operationB());
}
}
public class VisitorB extends Visitor{
@Override
public void visit(ElementA a) {
// TODO Auto-generated method stub
System.out.println("具体访问者B ->"+a.operationA());
}
@Override
public void visit(ElementB b) {
// TODO Auto-generated method stub
System.out.println("具体访问者B ->"+b.operationB());
}
}
public class ObjectStructure {
private List list = new ArrayList();
public void accept(Visitor visitor){
Iterator iteartor = list.iterator();
while(iteartor.hasNext()){
Element element = (Element) iteartor.next();
element.accept(visitor);
}
}
public void add(Element element){
list.add(element);
}
public void remove(Element element){
list.remove(element);
}
}
public class Main {
public static void main(String[] args) {
ObjectStructure os = new ObjectStructure();
os.add(new ElementA());
os.add(new ElementB());
Visitor visitor = new VisitorA();
os.accept(visitor);
}
}
运行结果:
具体访问者A ->具体元素A
具体访问者A ->具体元素B
分析:艺术公司利用“铜”可以设计出铜像,利用“纸”可以画出图画;造币公司利用“铜”可以印出铜币,利用“纸”可以印出纸币。
对“铜”和“纸”这两种元素,两个公司的处理方法不同,所以该实例用访问者模式来实现比较适合。
抽象访问者:Company
具体访问者:ArtCompany,RMBCompany
抽象元素角色:Material 材料类
具体元素角色:Paper、Cuprum
对象结构角色:SetMaterial
在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时候能将该状态恢复到保存状态,又叫快照模式
优点:
缺点:
//备忘录角色
public class Memento {
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public Memento(String state) {
super();
this.state = state;
}
}// 角色管理类
public class Manager {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
public Manager(Memento memento) {
super();
this.memento = memento;
}
public Manager() {
super();
}
}
//发起人
public class SendPeople {
private String state;
public Memento createMemento(){
Memento m = new Memento(state);
return m;
}
public void restoreMemento(Memento memento){
this.setState(memento.getState());
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
public class Main {
public static void main(String[] args) {
SendPeople sendp = new SendPeople();
Manager manager = new Manager();
sendp.setState("890");
System.out.println("初始状态 ="+sendp.getState());
manager.setMemento(sendp.createMemento());
sendp.setState("1111");
System.out.println("新的状态="+sendp.getState());
sendp.restoreMemento(manager.getMemento()); // 恢复状态
System.out.println("恢复状态="+sendp.getState());
}
}
运行结果:
初始状态 =890
新的状态=1111
恢复状态=890
给分析对象应以一个语言,并定义改语言的文法表示,再设计一个解释器来解析语言中的句子,也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。
这里提到的文法和句子的概念同编译原理中的描述相同,“文法”指语言的语法规则,而“句子”是语言集中的元素。
解释器模式是一种行为型模式。
优点:
缺点:
::= 的
::= 韶关|广州
::= 老人|妇女|儿童
注:这里的符号“::=”表示“定义为”的意思,用“〈”和“〉”括住的是非终结符,没有括住的是终结符。
// 抽象表达式
public abstract class Expression {
public abstract boolean intercepter(String info);
}
public class TerminalExpression extends Expression{
private Set list = new HashSet();
@Override
public boolean intercepter(String info) {
// TODO Auto-generated method stub
if(list.contains(info)){
return true;
}
return false;
}
public TerminalExpression(String[] data) {
for(int i = 0 ; i < data.length ; i++){
list.add(data[i]);
}
}
}
public class AndExpression extends Expression {
private Expression city;
private Expression persion;
@Override
public boolean intercepter(String info) {
// TODO Auto-generated method stub
String s[] = info.split("的");
return city.intercepter(s[0]) && persion.intercepter(s[1]);
}
public AndExpression(Expression city, Expression persion) {
super();
this.city = city;
this.persion = persion;
}
public Expression getCity() {
return city;
}
public void setCity(Expression city) {
this.city = city;
}
public Expression getPersion() {
return persion;
}
public void setPersion(Expression persion) {
this.persion = persion;
}
}
public class Context {
private String[] citys={"韶关","广州"};
private String[] persons={"老人","妇女","儿童"};
private Expression expression;
public Context() {
super();
Expression city = new TerminalExpression(citys);
Expression person = new TerminalExpression(persons);
expression = new AndExpression(city, person);
}
public void freeRide(String info){
boolean ok = expression.intercepter(info);
if(ok) System.out.println(info + ",本次免费乘车");
else System.out.println(info +",不是会员,赶下去");
}
public String[] getCitys() {
return citys;
}
public void setCitys(String[] citys) {
this.citys = citys;
}
public String[] getpPersons() {
return persons;
}
public void setPersons(String[] persion) {
this.persons = persion;
}
public Expression getExpression() {
return expression;
}
public void setExpression(Expression expression) {
this.expression = expression;
}
}
public class Main {
public static void main(String[] args) {
Context bus=new Context();
bus.freeRide("韶关的老人");
bus.freeRide("韶关的年轻人");
bus.freeRide("广州的妇女");
bus.freeRide("广州的儿童");
bus.freeRide("山东的儿童");
}
}
运行结果:
韶关的老人,本次免费乘车
韶关的年轻人,不是会员,赶下去
广州的妇女,本次免费乘车
广州的儿童,本次免费乘车
山东的儿童,不是会员,赶下去