Java设计模式,是一套由前人总结的,被反复使用的代码设计经验。它为我们解决一些实际问题提供了一些很好的设计模板,了解设计模式,有利于提高我们的代码设计能力,架构能力,更有可能自己能够设计出适合业务的一套设计模式。接下来就让我们了解一下这些神秘的设计模式。
总的来说,设计模式可以分为以下几大类。
创建型模式:
属于创建型模式的设计模式有单例模式,简单工厂模式,工厂方法模式,抽象工厂模式,原型模式,建造者模式。这些模式都是用来创建对象的,提供了方便的接口给客户端使用。创建型模式将对象的创建和使用分离,在使用对象时无需关心对象的创建细节,从而降低系统的耦合度,让设计方案更易于修改和扩展。
结构型模式:
属于结构型模式的设计模式有适配器模式,桥接模式,组合模式,装饰模式,外观模式,享元模式,代理模式。他们大多是用来组织某种结构,提供某种复杂的功能,不同的结构型模式关注如何将现有类或对象组织在一起形成更加强大的结构。比如适配器提供了将两个毫不相关的类或接口提供了桥梁,组合模式为树形结构提供了模板,外观模式为客户提供了方便简洁的接口,并且隐藏了内部细节。
行为型模式:
属于行为型模式的设计模式有职责链模式,命令模式,解释器模式,迭代器模式,中介者模式,备忘录模式,观察者模式,状态模式,策略模式,模板方法模式,访问者模式。这些模式为客户端提供了许多功能需求,注重对象之间的交互,关注他们之间的相互作用和职责划分。比如策略模式为用户提供了不同的策略选择,观察者模式,使得某个事件发生过后可以自动触发其他事件。又比如备忘录模式,使得用户可以恢复之前的某个状态,实现还原的功能。
接下来我们一个一个来看这些设计模式。
创造型模式
单例模式
需求:系统需要有一个恒定不变的对象,每次获取都是同一个对象。比如一个朝代只能有一个皇帝,一个公司只能有一个老板。那我们的系统就不能new出两个老板对象出来。windows系统的任务管理器便是实现了单例模式。
特点:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。而单例模式又分为两类,懒汉式和饿汉式。
饿汉式单例即一开始就new出一个实例,始终占据着内存,不管他以后是不是被用到。优点是不用考虑多线程的问题。
代码如下
public class EagerSingleton {
privatestatic final EagerSingleton instance=new EagerSingleton();
privateEagerSingleton(){}
publicstatic EagerSingleton getInstance(){
returninstance;
}
}
懒汉式单例即等到该对象第一次被使用时才new出一个实例,避免了一开始就占用资源。缺点是考虑多线程情况下同时new出多个实例的问题,需要使用锁,在多线程并发访问环境下会导致性能下降。
代码如下
public class LazySingleton {
privatestatic LazySingleton instance=null;
private LazySingleton(){}
synchronizedpublic static LazySingleton getInsatance(){
if(instance==null)instance =new LazySingleton();
returninstance;
}
}
IoDH(Initializationon Demand Holder):即有延迟加载,又保证线程安全,不影响系统性能。缺点是与编程语言本身特性相关,java中可以实现,但很多面向对象语言不支持。
public class IoDH {
privateIoDH(){}
privatestatic class HolderClass{
privatefinal static IoDH instance =new IoDH();
}
publicstatic IoDH getInsatance(){
returnHolderClass.instance;
}
}
简单工厂模式
需求:客户端想简单地传入不同参数就得到不同类的实例,不想很麻烦地一个一个去new。
特点:简单工厂针对抽象编程,使用static方法,根据传入的参数,new出对应的具体子类,用户可以通过Factory.Create(“对应参数”)得到对应实例,免除创建的职责。缺点是工厂类集中了大量创建代码,一旦不能正常工作整个系统都要受到影响。并且扩展十分困难,需要修改工厂逻辑。
示例代码如下:
abstract class Product {
public void methodSame(){
//公共方法
}
//抽象业务方法
public abstract void methodDiff();
}
public class ConcreteProduct1 extends Product{
@Override
public void methodDiff() {
// TODO Auto-generated method stub
System.out.println("我是第一号产品");
}
}
public class ConcreteProduct2 extends Product{
@Override
public void methodDiff() {
// TODO Auto-generated method stub
System.out.println("我是第二号产品");
}
}
public class Factory {
public static Product getProduct(String arg){
Product product =null;
if(arg.equalsIgnoreCase("1")){
product=new ConcreteProduct1();
}else if(arg.equalsIgnoreCase("2")){
product=new ConcreteProduct2();
}
return product;
}
}
public class Client {
public static void main(String[] args){
Product product1,product2;
product1=Factory.getProduct("1");
product2=Factory.getProduct("2");
product1.methodDiff();
product2.methodDiff();
}
}
工厂方法模式:
需求:同简单工厂模式。
特点:定义一个用于创建对象的接口,让子类决定将哪一个类实例化。在简单工厂模式中,有加入新产品需要修改工厂逻辑的缺点,在工厂方法模式中,我们不再使用同一个工厂,而是不同的产品提供不同的工厂,每当我们加入新产品时,只需要实现新的工厂类,不用改变原来的任何一处代码。它缺点是新增一个产品类还要提供与之对应的工厂类,个数将成对增加。
代码结构:抽象产品类(或接口)作为抽象工厂类(或接口)的创建方法的参数传入,再通过具体的工厂实现类来得到对应的具体产品类。
抽象工厂模式:
需求:在日常生活中,每个产品都有不同的牌子,而同一个牌子旗下可能有不同的产品,怎么去模拟这样一个模式?
特点: 在简单工厂模式的基础上新增两个概念,分别是产品族和产品等级结构。产品等级结构即产品的继承结构,即抽象产品类/接口与它的实现类。产品族可以理解为一个品牌,相同品牌旗下的不同产品构成一个产品族。在抽象工厂模式中,一个产品族是由同一个工厂生产的。增加新的产品族只需要增加一个新的工厂,无需修改已有系统,符合开闭原则。但是,增加新的产品等级结构却需要较大的修改,这是它的缺点。
示例代码如下:
public interface ComboBox {
publicvoid display();
}
public interface TextField {
publicvoid display();
}
public interface Button {
publicvoid display();
}
public class SpringButton implementsButton{
@Override
publicvoid display() {
//TODO Auto-generated method stub
System.out.println("显示浅绿色按钮");
}
}
public class SpringComboBox implementsComboBox{
@Override
publicvoid display() {
//TODO Auto-generated method stub
System.out.println("显示绿色边框组合框");
}
}
public class SpringTextField implementsTextField{
@Override
publicvoid display() {
//TODO Auto-generated method stub
System.out.println("显示绿色边框文本框。");
}
}
public class SummerButton implementsButton{
@Override
publicvoid display() {
//TODO Auto-generated method stub
System.out.println("显示浅蓝色按钮");
}
}
public class SummerComboBox implementsComboBox{
@Override
publicvoid display() {
//TODO Auto-generated method stub
System.out.println("显示蓝色边框组合框");
}
}
public class SummerTextField implementsTextField{
@Override
publicvoid display() {
//TODO Auto-generated method stub
System.out.println("显示蓝色边框文本框");
}
}
public interface SkinFactory {
publicButton createButton();
publicTextField createTextField();
publicComboBox createComboBox();
}
public class SpringSkinFactory implementsSkinFactory{
@Override
publicButton createButton() {
//TODO Auto-generated method stub
returnnew SpringButton();
}
@Override
publicTextField createTextField() {
//TODO Auto-generated method stub
returnnew SpringTextField();
}
@Override
publicComboBox createComboBox() {
//TODO Auto-generated method stub
returnnew SpringComboBox();
}
}
public class SummerSkinFactory implementsSkinFactory{
@Override
publicButton createButton() {
//TODO Auto-generated method stub
returnnew SummerButton();
}
@Override
publicTextField createTextField() {
//TODO Auto-generated method stub
returnnew SummerTextField();
}
@Override
publicComboBox createComboBox() {
//TODO Auto-generated method stub
returnnew SummerComboBox();
}
}
原型模式
需求:创建一个复杂对象比较麻烦或者成本较高,需要一个方法来简化对象创建的过程。或者是需要保存对象的状态。
特点:让对象实现Cloneable接口,重写Clone方法。适用clone方法需要注意的是,克隆分为浅克隆和深克隆。当一个对象中所含的数据都是基本类型数据时,调用clone方法不会有任何问题,这是所谓的浅克隆。当你数据中包含引用类型时,简单地调用clone方法只是会对象的引用复制过去,而不是真正的复制一个对象。以电视(对象)和遥控器(引用)为例,我们只是复制了一个遥控器,而没有复制电视。这样我们在对其修改的时候,克隆后的对象会改变被克隆对象的状态。而深克隆就是需要我们将电视也克隆一份,需要在类的clone方法中对引用的类也调用clone方法,或者直接用serializable将整个类序列化写入对象流中再读取出来。
浅克隆示例代码:
public class WeeklyLog implementsCloneable{
privateString name;
privateString date;
privateString content;
publicvoid setName(String name){
this.name=name;
}
publicvoid setDate(String date){
this.date=date;
}
publicvoid setContent(String content){
this.content=content;
}
publicString getName(){
returnthis.name;
}
publicString getDate(){
returnthis.date;
}
publicString getContent(){
returnthis.content;
}
publicWeeklyLog clone(){
Objectobj=null;
try{
obj=super.clone();
return(WeeklyLog)obj;
}
catch(Exception e) {
//TODO: handle exception
System.out.println("不支持复制!");
returnnull;
}
}
publicstatic void main(String[] args){
WeeklyLoglog =new WeeklyLog();
log.setName("小明");
log.setDate("第1周");
log.setContent("每天加班");
System.out.println("****周报****");
System.out.println("周次:"+log.getDate());
System.out.println("姓名:"+log.getName());
System.out.println("内容:"+log.getContent());
System.out.println("************");
WeeklyLoglog2 =log.clone();
log2.setDate("第2周");
System.out.println("****周报****");
System.out.println("周次:"+log2.getDate());
System.out.println("姓名:"+log2.getName());
System.out.println("内容:"+log2.getContent());
System.out.println("************");
}
}
深克隆示例代码:
public class Attachment implementsSerializable{
privateString name;
publicvoid setName(String name){
this.name=name;
}
publicString getName(){
returnname;
}
publicvoid download(){
System.out.println("下载附件:文件名为"+name);
}
}
public class WeeklyLog implementsCloneable,Serializable{
privateString name;
privateString date;
privateString content;
privateAttachment attachment;
publicvoid setAttachment(Attachment attachment){
this.attachment=attachment;
}
publicvoid setName(String name){
this.name=name;
}
publicvoid setDate(String date){
this.date=date;
}
publicvoid setContent(String content){
this.content=content;
}
publicString getName(){
returnthis.name;
}
publicString getDate(){
returnthis.date;
}
publicString getContent(){
returnthis.content;
}
publicAttachment getAttachment(){
returnthis.attachment;
}
publicWeeklyLog clone(){
Objectobj=null;
try{
obj=super.clone();
return(WeeklyLog)obj;
}
catch(Exception e) {
//TODO: handle exception
System.out.println("不支持复制!");
returnnull;
}
}
publicWeeklyLog deepClone() throws IOException, ClassNotFoundException{
ByteArrayOutputStreambao=new ByteArrayOutputStream();
ObjectOutputStreamoos=new ObjectOutputStream(bao);
oos.writeObject(this);
ByteArrayInputStreambis=new ByteArrayInputStream(bao.toByteArray());
ObjectInputStreamois=new ObjectInputStream(bis);
return(WeeklyLog)ois.readObject();
}
publicstatic void main(String[] args) throws ClassNotFoundException, IOException{
WeeklyLoglog =new WeeklyLog();
Attachmentattachment=new Attachment();
log.setAttachment(attachment);
log.setName("小明");
log.setDate("第1周");
log.setContent("每天加班");
System.out.println("****周报****");
System.out.println("周次:"+log.getDate());
System.out.println("姓名:"+log.getName());
System.out.println("内容:"+log.getContent());
System.out.println("************");
WeeklyLoglog2;
log2 = log.deepClone();
log2.setDate("第2周");
System.out.println("****周报****");
System.out.println("周次:"+log2.getDate());
System.out.println("姓名:"+log2.getName());
System.out.println("内容:"+log2.getContent());
System.out.println("************");
System.out.println("附件是否相同:"+(log.getAttachment()==log2.getAttachment()));
}
}
建造者模式:
需求:我(客户)想要造一辆车,但我不懂内部构造。
特点:将一个复杂对象的构建与它的表示分离,使得同样的构件过程可以创建不同的表示。客户端只需要实例化指挥者类,根据传入的具体的建造者类型,指挥者一步一步地构造一个完整的产品,相同的构造过程可以创造完全不同的产品。核心在于如何一步一步地构建一个包含多个组成部件的完整对象,使用相同的构造过程构造不同的产品。
优点:是用户完全不必要知道细节,并且可以方便地替换具体建造者或者增加建造者,符合开闭原则。所创造的产品必须是组成部分相似,如果很多组成部分不同则不适用。
适用场景:
①需要的生成对象有复杂的内部结构。
②需要生成的对象的属性相互依赖,需要指定其顺序。
③对象的创建过程独立于创建该对象的类。
④隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
示例代码:
public class Actor {
privateString type;
privateString sex;
privateString face;
privateString costume;
privateString hairStyle;
publicvoid setType(String type){
this.type=type;
}
publicvoid setSex(String sex){
this.sex=sex;
}
publicvoid setFace(String face){
this.face=face;
}
publicvoid setCostume(String costume){
this.costume=costume;
}
publicvoid setHairStyle(String hairStyle){
this.hairStyle=hairStyle;
}
publicString getType(){
returntype;
}
publicString getSex(){
returnsex;
}
publicString getFace(){
returnface;
}
publicString getCostume(){
return costume;
}
publicString getHairStyle(){
returnhairStyle;
}
}
abstract class ActorBuilder {
protectedActor actor=new Actor();
publicabstract void buildType();
publicabstract void buildSex();
publicabstract void buildFace();
publicabstract void buildCostume();
publicabstract void buildHairStyle();
publicActor createActor(){
returnactor;
}
}
public class AngelBuilder extendsActorBuilder{
publicvoid buildType(){
actor.setType("天使");
}
publicvoid buildSex(){
actor.setSex("女");
}
publicvoid buildFace(){
actor.setFace("漂亮");
}
publicvoid buildCostume(){
actor.setCostume("白裙");
}
publicvoid buildHairStyle(){
actor.setHairStyle("披肩长发");
}
}
public class HeroBuilder extendsActorBuilder{
publicvoid buildType(){
actor.setType("英雄");
}
publicvoid buildSex(){
actor.setSex("男");
}
publicvoid buildFace(){
actor.setFace("英俊");
}
publicvoid buildCostume(){
actor.setCostume("盔甲");
}
publicvoid buildHairStyle(){
actor.setHairStyle("飘逸");
}
}
public class DevilBuilder extendsActorBuilder{
publicvoid buildType(){
actor.setType("恶魔");
}
publicvoid buildSex(){
actor.setSex("妖");
}
publicvoid buildFace(){
actor.setFace("丑陋");
}
publicvoid buildCostume(){
actor.setCostume("黑衣");
}
publicvoid buildHairStyle(){
actor.setHairStyle("光头");
}
}
public class ActorController {
publicActor construct(ActorBuilder ab){
Actoractor;
ab.buildType();
ab.buildSex();
ab.buildFace();
ab.buildCostume();
ab.buildHairStyle();
actor=ab.createActor();
returnactor;
}
}
public class Client {
publicstatic void main(String[] args){
ActorBuilderab=new AngelBuilder();
ActorControllerac=new ActorController();
Actoractor;
actor=ac.construct(ab);
Stringtype=actor.getType();
System.out.println(type+"的外观:");
System.out.println("性别:"+actor.getSex());
System.out.println("面容:"+actor.getFace());
System.out.println("服装:"+actor.getCostume());
System.out.println("发型:"+actor.getHairStyle());
}
}
适配器模式
需求:我们拿到了客户提供的类,但是它又不太符合我们系统的接口,如何兼容?
特点:将一个接口转换成客户希望的另一个接口,使接口不兼容的类可以一起工作。类似电源适配器的作用。它是为了解决已经在运行中的项目问题,而不是一种还处在开发阶段时候应该考虑的设计模式。
适配器模式又可以分为类适配器和对象适配器。类适配器模式采用的是多重继承的方式,对象适配器采用的是组合的方式
类适配器示例代码:
public interface Target {
//目标自己有的方法
publicvoid request();
}
public class ConcreteTarget implementsTarget{
@Override
publicvoid request() {
//TODO Auto-generated method stub
System.out.println("Ifyou need and help,please call me!");
}
}
public class Adaptee {
publicvoid doSomething(){
System.out.println("I'mkind of busy,leave me alone,pls");
}
}
public class Adapter extends Adapteeimplements Target{
@Override
publicvoid request() {
//TODO Auto-generated method stub
super.doSomething();
}
}
public class Client {
publicstatic void main(String[] args){
Target target=new ConcreteTarget();
target.request();
Targettarget2=new Adapter();
target2.request();
}
}
对象适配器示例代码:
public interface IUserInfo {
StringgetUserName();
StringgetHomeAddress();
StringgetMobileNumber();
StringgetOfficeTelNumber();
StringgetJobPosition();
StringgetHomeTelNumber();
}
public interface IOuterUserBaseInfo {
publicMap getUserBaseInfo();
}
public interface IOuterUserOfficeInfo {
publicMap getUserOfficeInfo();
}
public interface IOuterUserHomeInfo {
publicMap getUserHomeInfo();
}
public class OuterUserBaseInfo implementsIOuterUserBaseInfo{
@Override
publicMap getUserBaseInfo() {
//TODO Auto-generated method stub
HashMapbaseInfoMap=new HashMap<>();
baseInfoMap.put("userName","这个员工叫混世魔王");
baseInfoMap.put("mobileNumber","这个员工电话是:……");
returnbaseInfoMap;
}
}
public class OuterUserHomeInfo implementsIOuterUserHomeInfo{
@Override
publicMap getUserHomeInfo() {
//TODO Auto-generated method stub
HashMaphomeInfo=new HashMap();
homeInfo.put("homeTelNumber", "员工的家庭电话是……");
homeInfo.put("homeAddress","员工的家庭地址是……");
returnhomeInfo;
}
}
public class OuterUserOfficeInfo implementsIOuterUserOfficeInfo{
@Override
publicMap getUserOfficeInfo() {
//TODO Auto-generated method stub
HashMapofficeInfo=new HashMap();
officeInfo.put("jobPosition","这个人的职位是boss");
officeInfo.put("officeTelNumber","员工的办公电话是……");
returnofficeInfo;
}
}
public class OuterUserInfo implementsIUserInfo{
privateIOuterUserHomeInfo homeInfo=null;
privateIOuterUserBaseInfo baseInfo=null;
privateIOuterUserOfficeInfo officeInfo=null;
privateMap baseMap=null;
privateMap homeMap=null;
privateMap officeMap=null;
publicOuterUserInfo(IOuterUserBaseInfo _baseInfo,IOuterUserHomeInfo_homeInfo,IOuterUserOfficeInfo _officeInfo) {
//TODO Auto-generated constructor stub
this.baseInfo=_baseInfo;
this.homeInfo=_homeInfo;
this.officeInfo=_officeInfo;
this.baseMap=this.baseInfo.getUserBaseInfo();
this.homeMap=this.homeInfo.getUserHomeInfo();
this.officeMap=this.officeInfo.getUserOfficeInfo();
}
@Override
publicString getUserName() {
//TODO Auto-generated method stub
StringuserName =(String)this.baseMap.get("userName");
System.out.println(userName);
returnuserName;
}
@Override
publicString getHomeAddress() {
//TODO Auto-generated method stub
StringhomeAddress =(String)this.homeMap.get("homeAddress");
System.out.println(homeAddress);
returnhomeAddress;
}
@Override
publicString getMobileNumber() {
//TODO Auto-generated method stub
StringmobileNumber =(String)this.baseMap.get("mobileNumber");
System.out.println(mobileNumber);
returnmobileNumber;
}
@Override
publicString getOfficeTelNumber() {
//TODO Auto-generated method stub
StringofficeTelNumber =(String)this.officeMap.get("officeTelNumber");
System.out.println(officeTelNumber);
returnofficeTelNumber;
}
@Override
publicString getJobPosition() {
//TODO Auto-generated method stub
StringjobPosition =(String)this.officeMap.get("jobPosition");
System.out.println(jobPosition);
returnjobPosition;
}
@Override
publicString getHomeTelNumber() {
//TODO Auto-generated method stub
StringhomeTelNumber =(String)this.homeMap.get("homeTelNumber");
System.out.println(homeTelNumber);
returnhomeTelNumber;
}
}
将IUserInfo接口和另外三个接口IOuterBase/Home/OfficeInfo结合起来。可以通过OuterUserInfo这个类实现IUserInfo接口,将IOuterBase/Home/OfficeInfo这三个接口的实现类组合起来。我们用接口的方法实现就可以调用传进来的那三个接口的数据来实现相同的功能。这种适配方式叫做对象适配器,它利用的是对象的组合关系,因此在设计时较为灵活。
桥梁模式:
需求:通常来说,不发生变化的代码可以通过继承来复用,但是我有一些代码不确定以后是否发生变化,应该怎么处理才能避免风险呢?
特点:将抽象部分与其实现部分分离,使他们都可以独立地变化。能够尽量地把变化的元素封装到最细,最小的逻辑单元中。它有优秀的扩充能力,可以增加实现也可以增加抽象,并且细节部分对用户是透明的。
示例代码:
public interface Implementor {
publicvoid doSomething();
publicvoid doAnything();
}
public class ConcreteImplementor1implements Implementor{
@Override
publicvoid doSomething() {
//TODO Auto-generated method stub
System.out.println("doSomething");
}
@Override
publicvoid doAnything() {
//TODO Auto-generated method stub
System.out.println("doAnything");
}
}
public class ConcreteImplementor2 implements Implementor{
@Override
publicvoid doSomething() {
}
@Override
publicvoid doAnything() {
}
}
public class Abstraction {
privateImplementor imp;
publicAbstraction(Implementor imp){
this.imp=imp;
}
publicvoid request(){
this.imp.doSomething();
}
publicImplementor getImp(){
returnimp;
}
}
public class RefinedAbstraction extendsAbstraction{
publicRefinedAbstraction(Implementor imp) {
super(imp);
//TODO Auto-generated constructor stub
}
@Override
publicvoid request(){
/*
* 业务处理……
*/
super.request();
super.getImp().doAnything();
}
}
组合模式:
需求:生活中有许多树形结构的例子,比如公司里面有总经理,总经理管理着研发部经理,销售部经理,市场部经理等,各经理又管理着许多组长,组长手下又有许多员工……如何表示这种树形结构?
特点:组合多个对象形成树形结构以表示具有“整体-部分”关系的层次结构。组合模式又分为安全组合模式和透明组合模式
安全组合模式:Component接口中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法,这种做法是安全的,因为根本不向叶子节点提供这些方法。缺点是不够透明,客户端不能完全针对抽象编程,必须有区别的对待叶子和容器。JAVA AWT中使用的组合模式就是安全组合模式。
示例代码如下:
public class Component {
//个体和整体都具有的共享
publicvoid doSomething(){
//编写业务逻辑
System.out.println("doSomething");
}
}
public class Composite extends Component{
privateArrayList componentArrayList=new ArrayList();
//增加一个叶子构件或树枝构件
publicvoid add(Component component){
this.componentArrayList.add(component);
}
//删除一个叶子构件或树枝构件
publicvoid remove(Component component){
this.componentArrayList.remove(component);
}
//获得分支下的所有叶子构件和树枝构件
publicArrayList getChildren(){
returnthis.componentArrayList;
}
}
public class Leaf extends Component{
//可以覆盖父类方法
privateString name;
publicLeaf(String name){
this.name=name;
}
@Override
publicvoid doSomething(){
System.out.println(name+":doSomething");
}
}
public class Client {
publicstatic void main(String[] args){
//创建一个根节点
Compositeroot =new Composite();
//创建树枝构件
Compositebranch=new Composite();
Compositebranch2=new Composite();
//创建叶子节点
Leafleaf1=new Leaf("1");
Leafleaf2=new Leaf("2");
Leafleaf3=new Leaf("3");
root.add(branch);
root.add(leaf2);
branch.add(leaf1);
branch.add(branch2);
branch2.add(leaf3);
display(root);
}
publicstatic void display(Composite root){
for(Componentc:root.getChildren()){
if(cinstanceof Leaf){
c.doSomething();
}else{
display((Composite)c);
}
}
}
}
透明组合模式中,抽象构件Component 中声明了所有用于管理成员对象的方法,包括add,remove,getChildren方法,确保所有的构件类都有相同的接口,在客户端看来叶子和容器都是一样的,可以透明地对待两者。它的缺点是不够安全,因为叶子和容器本质上是有区别的,叶子不可能有下一层的对象,对它调用add,remove,getChildren等方法是没有意义的,编译阶段没问题,如果在运行期间调用则会出错。(如果没有提供相应的错误处理代码)
示例代码:
public abstract class Component {
publicvoid doSomething(){
//编写业务逻辑
}
publicabstract void add(Component component);
publicabstract void remove(Component component);
publicabstract ArrayList getChildren();
}
public class Composite extends Component{
privateArrayList componentArrayList=new ArrayList();
//增加一个叶子构件或树枝构件
publicvoid add(Component component){
this.componentArrayList.add(component);
}
//删除一个叶子构件或树枝构件
publicvoid remove(Component component){
this.componentArrayList.remove(component);
}
//获得分支下的所有叶子构件和树枝构件
publicArrayList getChildren(){
returnthis.componentArrayList;
}
}
public class Leaf extends Component{
@Deprecated
publicvoid add(Component component) throws UnsupportedOperationException{
//TODO Auto-generated method stub
thrownew UnsupportedOperationException();
}
@Deprecated
publicvoid remove(Component component)throws UnsupportedOperationException {
//TODO Auto-generated method stub
thrownew UnsupportedOperationException();
}
@Deprecated
publicArrayList getChildren() throws UnsupportedOperationException{
//TODO Auto-generated method stub
thrownew UnsupportedOperationException();
}
}
public class Client {
publicstatic void display(Component root){
for(Componentc:root.getChildren()){
if(cinstanceof Leaf){
c.doSomething();
}else{
display(c);
}
}
}
}
装饰模式
需求:我想要很方便地扩展一个类的功能或者删除功能,并且他们可以独立地变化,怎么实现呢?
特点:动态地给一个对象增加一些额外的职责。装饰模式降低了系统 的耦合度,可以动态地增加和删除对象的职责,并且使得需要装饰的具体构件类和具体装饰类可以独立变化,以便增加新的具体构件和具体装饰类。JAVA IO流,javax、swing包中一些图形界面构件功能都运用了装饰模式。
优点:
①对于扩展一个类的功能,装饰模式更为灵活,不会导致类的个数急剧增加。
②对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合得到功能更为强大的对象。
③符合开闭原则。
缺点:
对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为繁琐。
适用场景:
①在不影响其他对象的情况下,以动态,透明地方式给单个对象添加职责。
②当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以适用装饰模式。
示例代码:
abstractclass Component {
public abstract void display();
}
publicclass ListBox extends Component{
public void display(){
System.out.println("显示列表框!");
}
}
publicclass TextBox extends Component{
public void display(){
System.out.println("显示文本框!");
}
}
publicclass Window extends Component{
public void display(){
System.out.println("显示窗体!");
}
}
publicclass ComponentDecorator extends Component{
private Component component;
public ComponentDecorator(Component component){
this.component=component;
}
public void display(){
component.display();
}
}
publicclass ScrollBarDecorator extends ComponentDecorator{
public ScrollBarDecorator(Component component){
super(component);
}
public void display(){
this.setScrollBar();
super.display();
}
public void setScrollBar(){
System.out.println("为构件增加滚动条");
}
}
publicclass BlackBorderDecorator extends ComponentDecorator{
public BlackBorderDecorator(Componentcomponent){
super(component);
}
public void display(){
this.setBlackBorder();
super.display();
}
public void setBlackBorder(){
System.out.println("为构件增加黑色边框");
}
}
publicclass Client {
public static void main(String[] args){
Component component ,component2,component3;
component=new Window();
component2=newScrollBarDecorator(component);
//component2.display();
component3=newBlackBorderDecorator(component2);
component3.display();
}
}
外观模式:
需求:我(客户)想要寄信,可是需要好多步骤啊,要写信,填写收件人地址和姓名,把信装入信封中,邮递信件..有没有一次性解决这些事情的方法?
特点:外部与一个子系统的通信通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的入口。不改变子系统对外暴露的接口,只改变内部的处理逻辑,这就是外观模式。
优点:
①减少系统间互相依赖。
②提高了安全性。不管系统内部如何变化,只要不影响到门面对象即可。并且客户只能访问门面对象上的方法。
缺点:
不遵循开闭原则,依赖门面对象,如果门面对象设计不好,只能对其进行修改,风险很大。
示例代码:
publicinterface ILetterProcess {
//首先要写信的内容
public void writeContent(String context);
//其次写封信
public void fillEnvelope(String address);
//把信放到信封里
public void letterIntoEnvelope();
//然后邮递
public void sendLetter();
}
publicclass LetterProcessImpl implements ILetterProcess{
@Override
public void writeContent(String context) {
// TODO Auto-generated method stub
System.out.println("填写信的内容:"+context);
}
@Override
public void fillEnvelope(String address) {
// TODO Auto-generated method stub
System.out.println("填写收件人地址及姓名:"+address);
}
@Override
public void letterIntoEnvelope() {
// TODO Auto-generated method stub
System.out.println("把信放入信封中……");
}
@Override
public void sendLetter() {
// TODO Auto-generated method stub
System.out.println("邮递信件……");
}
}
publicclass ModenPostOffice {
private ILetterProcess letterProcess=newLetterProcessImpl();
public void sendLetter(String context,Stringaddress){
letterProcess.writeContent(context);
letterProcess.fillEnvelope(address);
letterProcess.letterIntoEnvelope();
letterProcess.sendLetter();
}
}
publicclass Client {
public static void main(String[] args){
ModenPostOffice modenPostOffice=newModenPostOffice();
String address="广东省SCAU";
String context="hello world!";
modenPostOffice.sendLetter(context, address);
}
}
享元模式
需求:有很多相似甚至完全一样的对象,但我不想浪费空间,每次都要new一个新的完全一样的对象出来。
特点:运用共享技术有效地支持大量细粒度对象的复用。在享元模式中有以下两个概念
内部状态:不会随环境而改变的状态,比如字符串a永远是a。
外部状态:随环境改变,不可以共享的状态,比如字符串a的颜色,大小等。
优点:
极大地减少内存中对象的数量,使得相同或相似对象在内存中只保存一份从而节约资源。
缺点:
①需要分离出内部状态和外部状态,使得程序逻辑复杂。
②为了使对象共享,需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。
适用场景:
①一个系统有大量相同或者相似对象,内存大量浪费。
②对象的大部分状态都可以外部化,可以将这些外部对象传入对象中。
③需要多次重复使用享元对象。
示例代码:
abstract class IgoChessman {
publicabstract String getColor();
publicvoid display(Coordinates coordinates){
System.out.println("棋子颜色:"+this.getColor()+",棋子位置:"+coordinates.getX()+","+coordinates.getY());
}
}
public class BlackIgoChessman extendsIgoChessman{
publicString getColor(){
return"黑色";
}
}
public class WhiteIgoChessman extends IgoChessman{
publicString getColor(){
return"白色";
}
}
public class IgoChessmanFactory {
privatestatic IgoChessmanFactory instance=new IgoChessmanFactory();
privatestatic Hashtable ht;
privateIgoChessmanFactory(){
ht=newHashtable();
IgoChessmanblack,white;
black=newBlackIgoChessman();
ht.put("b",black);
white=newWhiteIgoChessman();
ht.put("w",white);
}
publicstatic IgoChessmanFactory getInstance(){
returninstance;
}
publicstatic IgoChessman getIgoChessman(String color){
return(IgoChessman)ht.get(color);
}
}
public class Coordinates {
privateint x,y;
publicCoordinates(int x,int y){
this.x=x;
this.y=y;
}
publicint getX(){
returnx;
}
publicint getY(){
returny;
}
publicvoid setX(int x){
this.x=x;
}
publicvoid setY(int y){
this.y=y;
}
}
public class Client {
publicstatic void main(String[] args){
IgoChessmanblack1,black2,black3,white1,white2;
IgoChessmanFactoryfactory;
//获取享元工厂对象
factory=IgoChessmanFactory.getInstance();
//通过享元工厂获取3颗黑子
black1=factory.getIgoChessman("b");
black2=factory.getIgoChessman("b");
black3=factory.getIgoChessman("b");
System.out.println("判断两颗黑子是否相同:"+(black1==black2));
white1=factory.getIgoChessman("w");
white2=factory.getIgoChessman("w");
System.out.println("判断两颗白子是否相同: "+(white1==white2));
black1.display(newCoordinates(1, 2));
black2.display(newCoordinates(3, 4));
black3.display(newCoordinates(1, 3));
white1.display(newCoordinates(2, 5));
white2.display(new Coordinates(2, 4));
}
}
代理模式
特点:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式的应用实在是太多了,在JavaWeb,Spring框架中都大量使用了代理模式。它有很多种模式,比如保护代理,远程代理,虚拟代理,动态代理,个性代理等。个性代理它在代理用户的基础上,有着它自己的功能,例如收费,代理用户之后,有个性功能的代理可以将自己的功能施加到用户身上,进行一些控制。下面的示例代码以个性代理为例,它实现了个性代理在游戏玩家升级的时候进行扣费的功能。
示例代码:
public interface IGamePlayer {
publicvoid login(String user,String password);
publicvoid killBoss();
publicvoid upgrade();
publicIGamePlayer getProxy();
}
public class GamePlayer implementsIGamePlayer{
privateString name="";
privateIGamePlayer proxy=null;
public GamePlayer(String name) {
//TODO Auto-generated constructor stub
this.name=name;
}
publicIGamePlayer getProxy(){
this.proxy=newGamePlayerProxy(this);
returnthis.proxy;
}
publicboolean isProxy(){
if(this.proxy==null)return false;
returntrue;
}
@Override
publicvoid login(String user, String password) {
//TODO Auto-generated method stub
if(this.isProxy())
System.out.println("登录名为"+user+"的用户"+this.name+"登录成功");
else
System.out.println("请使用指定的代理访问");
}
@Override
publicvoid killBoss() {
//TODO Auto-generated method stub
if(this.isProxy())
System.out.println(this.name+"在打怪!");
else
System.out.println("请使用指定的代理访问");
}
@Override
publicvoid upgrade() {
//TODO Auto-generated method stub
if(this.isProxy())
System.out.println(this.name+"又升了一级!");
else
System.out.println("请使用指定的代理访问");
}
}
public interface IProxy {
publicvoid count();
}
public class GamePlayerProxy implementsIGamePlayer,IProxy{
privateIGamePlayer gamePlayer=null;
publicGamePlayerProxy(IGamePlayer gamePlayer) {
this.gamePlayer=gamePlayer;
}
@Override
publicvoid login(String user, String password) {
//TODO Auto-generated method stub
this.gamePlayer.login(user,password);
}
@Override
publicvoid killBoss() {
//TODO Auto-generated method stub
this.gamePlayer.killBoss();
}
@Override
publicvoid upgrade() {
//TODO Auto-generated method stub
this.gamePlayer.upgrade();
this.count();
}
@Override
publicIGamePlayer getProxy() {
//TODO Auto-generated method stub
returnthis;
}
@Override
publicvoid count() {
//TODO Auto-generated method stub
System.out.println("升级总费用是:150元!");
}
}
public class Client {
publicstatic void main(String[] args){
IGamePlayerplayer=new GamePlayer("萌凯");
IGamePlayerproxy1=player.getProxy();
System.out.println("开始时间是:"+new Date());
proxy1.login("MK","password");
proxy1.killBoss();
proxy1.upgrade();
System.out.println("结束时间是:"+new Date());
}
}
行为型模式
职责链模式
需求:有很多对象可以处理我的请求,我应该将该请求发给谁呢?
特点:避免将请求发送者与接受者耦合在一起,让多个对象都有机会接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
优点:
①一个对象无须知道是其他哪一个对象处理其请求,对象仅需知道该请求会被处理即可。接受者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,由客户端负责创建,降低系统的耦合度。
②请求处理对象仅需要维持一个指向后继者的引用,简化连接。
③在给对象分派职责时,职责链可以提供灵活性。通过在运行时对链进行动态地增加或修改或改变处理一个请求的职责。
④在系统中增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新连接链即可。
缺点:
①由于一个请求没有明确的接受者,不能保证它一定会被处理,也可能因为职责连没有被正确配置而得不到处理。
②对于比较长的职责链,请求的处理可能涉及多个对象,系统性能将受到一定影响。
③职责链连接不当可能造成死循环。
适用场景:
①有多个对象可以处理同一个请求。
②不明确指定接收者的情况下,向其中一个提交请求。
③动态指定一组对象出来请求,客户端可以动态创建责任链,还可以改变处理者的顺序。
示例代码:
abstract class Approver {
protectedApprover successor;//后继对象
protectedString name;
publicApprover(String name){
this.name=name;
}
publicvoid setSuccessor(Approver successor){
this.successor=successor;
}
publicabstract void processRequest(PurchaseRequest request);
}
public class Director extends Approver{
publicDirector(String name){
super(name);
}
publicvoid processRequest(PurchaseRequest request){
if(request.getAmount()<50000){
System.out.println("主任"+this.name+"审批购物单:"+request.getNumber()+
"金额:"+request.getNumber()+"元,采购目的:"+request.getPurpose()+".");
}else{
this.successor.processRequest(request);//转发请求
}
}
}
public class VicePresident extendsApprover{
publicVicePresident(String name){
super(name);
}
publicvoid processRequest(PurchaseRequest request){
if(request.getAmount()<100000){
System.out.println("副董事长"+this.name+"审批购物单:"+request.getNumber()+
"金额:"+request.getNumber()+"元,采购目的:"+request.getPurpose()+".");
}else{
this.successor.processRequest(request);//转发请求
}
}
}
public class President extends Approver{
publicPresident(String name){
super(name);
}
publicvoid processRequest(PurchaseRequest request){
if(request.getAmount()<500000){
System.out.println("董事长"+this.name+"审批购物单:"+request.getNumber()+
"金额:"+request.getNumber()+"元,采购目的:"+request.getPurpose()+".");
}else{
this.successor.processRequest(request);//转发请求
}
}
}
public class Congress extends Approver{
publicCongress(String name){
super(name);
}
publicvoid processRequest(PurchaseRequest request){
System.out.println("召开董事会审批购物单:"+request.getNumber()+
"金额:"+request.getNumber()+"元,采购目的:"+request.getPurpose()+".");
}
}
public class PurchaseRequest {
privatedouble amount;
privateint number;
privateString purpose;
publicPurchaseRequest(double amount,int number,String purpose){
this.amount=amount;
this.number=number;
this.purpose=purpose;
}
publicvoid setAmount(double amount){
this.amount=amount;
}
publicdouble getAmount(){
returnamount;
}
publicvoid setNumber(int number){
this.number=number;
}
publicint getNumber(){
returnnumber;
}
publicvoid setPurpose(String purpose){
this.purpose=purpose;
}
publicString getPurpose(){
returnpurpose;
}
}
public class Client {
publicstatic void main(String[] args){
Approverwjzhang,gyang,jguo,meeting;
wjzhang=newDirector("wjzhang");
gyang=newVicePresident("gyang");
jguo=newPresident("jguo");
meeting=newCongress("meeting");
//创造责任链
wjzhang.setSuccessor(gyang);
gyang.setSuccessor(jguo);
jguo.setSuccessor(meeting);
PurchaseRequestpr1=new PurchaseRequest(45000, 10001, "购买倚天剑");
wjzhang.processRequest(pr1);
PurchaseRequestpr2=new PurchaseRequest(60000, 10001, "购买屠龙刀");
wjzhang.processRequest(pr2);
PurchaseRequestpr3=new PurchaseRequest(160000, 10001, "购买九阴真经");
wjzhang.processRequest(pr3);
PurchaseRequestpr4=new PurchaseRequest(800000, 10001, "购买桃花岛");
wjzhang.processRequest(pr4);
}
}
命令模式
需求:我(客户)有时想要改需求,有时想要增加功能,有时想要删除页面,但我又不想每次都要亲自去找到对应的组别来发出命令,我需要一个跑腿的人来替我执行。
特点:将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。
优点:
①类间解耦,调用者和接受者没有任何依赖关系,调用者只需要调用Command抽象类的execute方法
②可拓展性,Command的子类可以非常容易拓展,而调用者Invoker和高层次的模块Client不产生严重的代码耦合。
③命令模式可以结合其他模式比如责任链模式,实现命令族解析任务,或者结合模板方法模式,则可以减少Command子类膨胀问题。
缺点:
有N个命令就有N个子类。
适用场景:
只要认为是命令的地方就可以使用命令模式,比如模拟DOS系统,GUI开发。
示例代码:
public abstract class Group {
//甲乙双方分开办公,如果你要和某个组讨论,需要先找到这个组
publicabstract void find();
//按要求增加功能
publicabstract void add();
//按要求删除功能
publicabstract void delete();
//按要求修改功能
publicabstract void change();
//按要求给出所有的变更计划
publicabstract void plan();
}
public class PageGroup extends Group{
@Override
publicvoid find() {
//TODO Auto-generated method stub
System.out.println("找到美工组……");
}
@Override
publicvoid add() {
//TODO Auto-generated method stub
System.out.println("客户要求增加一个页面……");
}
@Override
publicvoid delete() {
//TODO Auto-generated method stub
System.out.println("客户要求修改一个页面……");
}
@Override
publicvoid change() {
//TODO Auto-generated method stub
System.out.println("客户要求删除一个页面……");
}
@Override
publicvoid plan() {
//TODO Auto-generated method stub
System.out.println("客户要求页面变更计划……");
}
}
public class RequirementGroup extendsGroup{
@Override
publicvoid find() {
//TODO Auto-generated method stub
System.out.println("找到需求组……");
}
@Override
publicvoid add() {
//TODO Auto-generated method stub
System.out.println("客户要求增加一项需求……");
}
@Override
publicvoid delete() {
//TODO Auto-generated method stub
System.out.println("客户要求删除一项需求……");
}
@Override
publicvoid change() {
//TODO Auto-generated method stub
System.out.println("客户要求修改一项需求……");
}
@Override
publicvoid plan() {
//TODO Auto-generated method stub
System.out.println("客户要求需求变更计划……");
}
}
public class CodeGroup extends Group{
@Override
publicvoid find() {
//TODO Auto-generated method stub
System.out.println("找到代码组……");
}
@Override
publicvoid add() {
//TODO Auto-generated method stub
System.out.println("客户要求增加一项功能……");
}
@Override
publicvoid delete() {
//TODO Auto-generated method stub
System.out.println("客户要求删除一项功能……");
}
@Override
publicvoid change() {
//TODO Auto-generated method stub
System.out.println("客户要求修改一项功能……");
}
@Override
publicvoid plan() {
//TODO Auto-generated method stub
System.out.println("客户要求代码变更计划……");
}
}
public abstract class Command {
protectedRequirementGroup rg=new RequirementGroup();
protectedPageGroup pg =new PageGroup();
protectedCodeGroup cg =new CodeGroup();
publicabstract void execute();
}
public class AddRequirementCommand extendsCommand{
publicvoid execute(){
super.rg.find();
super.rg.add();
super.rg.plan();
}
}
public class DeletePageCommand extendsCommand{
publicvoid execute(){
super.rg.find();
super.rg.delete();
super.rg.plan();
}
}
//跑腿的
public class Invoker{
privateCommand command;
publicvoid setCommand(Command command){
this.command=command;
}
publicvoid action(){
this.command.execute();
}
}
public class Client {
publicstatic void main(String[] args){
Invokerinvoker=new Invoker();
System.out.println("--------客户要求增加一项需求----------");
Commandcommand=new AddRequirementCommand();
invoker.setCommand(command);
invoker.action();
System.out.println("--------客户要求删除一个页面----------");
Commandcommand2=new DeletePageCommand();
invoker.setCommand(command2);
invoker.action();
}
}
解释器模式:
特点:定义一个语言的文法,并且建立一个解释器来解释该语言中的句子。解释器模式在实际的系统开发中使用得非常少,因为它会引起效率、性能以及维护等问题,一般在大中型的框架型项目能够找到它的身影,如一些数据分析工具、报表设计工具、科学计算工具等
优点:
简单语法分析工具,最显著的优点就是其扩展性,修改语法规则只需要修改相对应的非终结符表达式就可以,若扩展语法,只需要增加非终结符类就可以了。(非终结符即不能继续往下推导的元素)
缺点:
①类膨胀。每个语法都要产生一个非终结符表达式。
②解释器模式采用递归调用方法,导致调试非常复杂。
③效率,使用大量的循环和递归,分析冗长语法时效率难以忍受。
适用场景:
重复发生的问题可以使用解释器模式。例如,多个应用服务器,每天产生大量的日志,需要对日志文件进行分析处理,由于各个服务器的日志格式不同,但是数据要素是相同的,按照解释器的说法就是终结符表达式都是相同的,但是非终结符表达式就需要制定了。在这种情况下,可以通过程序来一劳永逸地解决该问题。
示例代码:
public abstract class Expression {
publicabstract int interpreter(HashMap var);
}
public abstract class SymbolExpressionextends Expression{
protectedExpression left;
protectedExpression right;
publicSymbolExpression(Expression left,Expression right){
this.left=left;
this.right=right;
}
}
public class SubExpression extendsSymbolExpression{
publicSubExpression(Expression left,Expression right){
super(left,right);
}
publicint interpreter(HashMap var){
returnsuper.left.interpreter(var)-super.right.interpreter(var);
}
}
public class AddExpression extendsSymbolExpression{
publicAddExpression(Expression left,Expression right){
super(left,right);
}
publicint interpreter(HashMap var){
returnsuper.left.interpreter(var)+super.right.interpreter(var);
}
}
public class VarExpression extendsExpression{
privateString key;
publicVarExpression(String key){
this.key=key;
}
publicint interpreter(HashMap var){
returnvar.get(this.key);
}
}
public class Calculator {
privateExpression expression;
publicCalculator(String expStr){
Stackstack=new Stack();
char[]charArray=expStr.toCharArray();
Expressionleft=null;
Expressionright=null;
for(inti=0;i var){
returnthis.expression.interpreter(var);
}
}
public class Client {
publicstatic void main(String[] args) throws IOException{
StringexpStr=getExpStr();
HashMap var=getValue(expStr);
Calculatorcalculator=new Calculator(expStr);
System.out.println("运算结果为:"+expStr+"="+calculator.run(var));
}
publicstatic String getExpStr()throws IOException{
System.out.print("请输入表达式:");
return(new BufferedReader(new InputStreamReader(System.in))).readLine();
}
publicstatic HashMap getValue(String expStr) throwsIOException{
HashMap map=new HashMap();
for(charch:expStr.toCharArray()){
if(ch!='+'&&ch!='-'){
if(!map.containsKey(String.valueOf(ch))){
System.out.print("请输入"+ch+"的值:");
Stringin=(new BufferedReader(new InputStreamReader(System.in))).readLine();
map.put(String.valueOf(ch),Integer.valueOf(in));
}
}
}
returnmap;
}
}
迭代器模式:
特点:提供一种方法来访问聚合对象,而不用暴露这个对象的内部。Java把迭代器模式已经融入到基本API中了,我们才能如此轻松、便捷。Java已经把迭代器给我们准备好了,我们再去写迭代器,就有点多余了。所以呀,这个迭代器模式也有点没落了,基本上很少有项目再独立写迭代器了,直接使用Collection下的实现类就可以完美地解决问题
示例代码:
public interface Iterator {
//遍历到下一个元素
publicObject next();
//是否已经遍历到尾部
publicboolean hasNext();
//删除当前指向的元素
publicboolean remove();
}
public class ConcreteIterator implementsIterator {
privateVector vector = new Vector();
//定义当前游标
publicint cursor = 0;
@SuppressWarnings("unchecked")
publicConcreteIterator(Vector _vector) {
this.vector= _vector;
}
//判断是否到达尾部
publicboolean hasNext() {
if(this.cursor == this.vector.size()) {
returnfalse;
}else {
returntrue;
}
}
//返回下一个元素
publicObject next() {
Objectresult = null;
if(this.hasNext()) {
result= this.vector.get(this.cursor++);
}else {
result= null;
}
returnresult;
}
//删除当前元素
publicboolean remove() {
this.vector.remove(this.cursor);
returntrue;
}
}
public interface Aggregate {
//是容器必然有元素的增加
publicvoid add(Object object);
//减少元素
publicvoid remove(Object object);
//由迭代器来遍历所有的元素
publicIterator iterator();
}
public class ConcreteAggregate implementsAggregate {
//容纳对象的容器
privateVector vector = new Vector();
//增加一个元素
publicvoid add(Object object) {
this.vector.add(object);
}
//返回迭代器对象
publicIterator iterator() {
returnnew ConcreteIterator(this.vector);
}
//删除一个元素
publicvoid remove(Object object) {
this.remove(object);
}
}
public class Client {
publicstatic void main(String[] args) {
//声明出容器
Aggregateagg = new ConcreteAggregate();
//产生对象数据放进去
agg.add("abc");
agg.add("aaa");
agg.add("1234");
//遍历一下
Iteratoriterator = agg.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
中介者模式:
需求:在一个系统中,如果类与类之间的耦合过多,他们之间的关系形成一张蜘蛛网,对维护起来肯定很不方便。在这种情况下,如何简化类与类之间的耦合?
特点:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地互相引用,从而使其耦合松散,而且可以独立地改变它们的交互。
优点:
减少类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只依赖中介者,减少了依赖,当然同时也降低了类间的耦合。
缺点:
中介者会膨胀得很大,而且逻辑复杂,原本N个对象直接的相互依赖关系转换为中介者和同事类的依赖关系,同事类越多,中介者的逻辑就越复杂。
适用情况:
在类图中出现了蜘蛛网状结构。在这种情况下一定要考虑使用中介者模式,这有利于把蜘蛛网梳理为星型结构,使原本复杂混乱的关系变得清晰简单。有以下应用场景:机场调度中心,MVC框架中的C,媒体网关,中介服务
示例代码:
public abstract class AbstractColleague {
protectedAbstractMediator mediator;
publicAbstractColleague(AbstractMediator _mediator) {
this.mediator= _mediator;
}
}
public class Purchase extendsAbstractColleague {
publicPurchase(AbstractMediator _mediator) {
super(_mediator);
}
//采购IBM电脑
publicvoid buyIBMcomputer(int number) {
super.mediator.execute("purchase.buy",number);
}
//不再采购IBM电脑
publicvoid refuseBuyIBM() {
System.out.println("不再采购IBM电脑");
}
}
public class Sale extends AbstractColleague{
publicSale(AbstractMediator _mediator) {
super(_mediator);
}
//销售IBM电脑
publicvoid sellIBMComputer(int number) {
super.mediator.execute("sale.sell",number);
System.out.println("销售IBM电脑" + number + "台");
}
//反馈销售情况,0~100变化,0代表根本就没人买,100代表非常畅销,出一个卖一个
publicint getSaleStatus() {
Randomrand = new Random(System.currentTimeMillis());
intsaleStatus = rand.nextInt(100);
System.out.println("IBM电脑的销售情况为:" + saleStatus);
returnsaleStatus;
}
//折价处理
publicvoid offSale() {
super.mediator.execute("sale.offsell");
}
}
public class Stock extendsAbstractColleague {
publicStock(AbstractMediator _mediator) {
super(_mediator);
}
//刚开始有100台电脑
privatestatic int COMPUTER_NUMBER = 100;
//库存增加
publicvoid increase(int number) {
COMPUTER_NUMBER= COMPUTER_NUMBER + number;
System.out.println("库存数量为:" + COMPUTER_NUMBER);
}
//库存降低
publicvoid decrease(int number) {
COMPUTER_NUMBER= COMPUTER_NUMBER - number;
System.out.println("库存数量为:" + COMPUTER_NUMBER);
}
//获得库存数量
publicint getStockNumber() {
returnCOMPUTER_NUMBER;
}
//存货压力大了,就要通知采购人员不要采购,销售人员要尽快销售
publicvoid clearStock() {
System.out.println("清理存货数量为:" + COMPUTER_NUMBER);
super.mediator.execute("stock.clear");
}
}
public abstract class AbstractMediator {
protectedPurchase purchase;
protectedSale sale;
protectedStock stock;
//构造函数
publicAbstractMediator() {
purchase= new Purchase(this);
sale= new Sale(this);
stock= new Stock(this);
}
//中介者最重要的方法叫做事件方法,处理多个对象之间的关系
publicabstract void execute(String str, Object... objects);
}
public class Mediator extends AbstractMediator{
//中介者最重要的方法
publicvoid execute(String str, Object... objects) {
if(str.equals("purchase.buy")) { // 采购电脑
this.buyComputer((Integer)objects[0]);
}else if (str.equals("sale.sell")) { // 销售电脑
this.sellComputer((Integer)objects[0]);
}else if (str.equals("sale.offsell")) { // 折价销售
this.offSell();
}else if (str.equals("stock.clear")) { // 清仓处理
this.clearStock();
}
}
//采购电脑
privatevoid buyComputer(int number) {
intsaleStatus = super.sale.getSaleStatus();
if(saleStatus > 80) { // 销售情况良好
System.out.println("采购IBM电脑:" + number + "台");
super.stock.increase(number);
}else { // 销售情况不好
intbuyNumber = number / 2; // 折半采购
System.out.println("采购IBM电脑:" + buyNumber + "台");
}
}
//销售电脑
privatevoid sellComputer(int number) {
if(super.stock.getStockNumber() < number) { // 库存数量不够销售
super.purchase.buyIBMcomputer(number);
}
super.stock.decrease(number);
}
//折价销售电脑
privatevoid offSell() {
System.out.println("折价销售IBM电脑" + stock.getStockNumber() +"台");
}
//清仓处理
privatevoid clearStock() {
//要求清仓销售
super.sale.offSale();
//要求采购人员不要采购
super.purchase.refuseBuyIBM();
}
}
public class Client {
publicstatic void main(String[] args) {
AbstractMediatormediator = new Mediator();
//采购人员采购电脑
System.out.println("------采购人员采购电脑--------");
Purchasepurchase = new Purchase(mediator);
purchase.buyIBMcomputer(100);
//销售人员销售电脑
System.out.println("\n------销售人员销售电脑--------");
Salesale = new Sale(mediator);
sale.sellIBMComputer(1);
//库房管理人员管理库存
System.out.println("\n------库房管理人员清库处理--------");
Stockstock = new Stock(mediator);
stock.clearStock();
}
}
备忘录模式:
特点:在不破坏封装的情况下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将该对象回复到原先保存的状态。提供一个可回滚(rollback)的操作;比如Word中的CTRL+Z组合键,IE浏览器中的后退按钮,文件管理器上的backspace键等,数据库连接的事务管理就是用的备忘录模式
优点:
①提供了状态恢复的机制,使得用户可以回到一个特定的历史步骤。
②实现了对信息的封装,一个备忘录对象不会被其他代码所改动,采用列表,堆栈等集合来储存备忘录对象可以实现多种撤销操作。如果单一的备份不能满足要求,只要把Caretaker管理员中容纳备忘录的容器改为一个Map即可。
缺点:
资源消耗过大,需要保存的类的成员变量过多,就不可避免地需要占用大量存储空间,每保存一次对象的状态都需要消耗一定的系统资源。
示例代码:
public class Memento {
//男孩的状态
privateString state = "";
//通过构造函数传递状态信息
publicMemento(String _state) {
this.state= _state;
}
publicString getState() {
returnstate;
}
publicvoid setState(String state) {
this.state= state;
}
}
public class Boy {
//男孩的状态
privateString state = "";
//认识女孩子后状态肯定改变,比如心情、手中的花等
publicvoid changeState() {
this.state= "心情可能很不好";
}
publicString getState() {
returnstate;
}
publicvoid setState(String state) {
this.state= state;
}
//保留一个备份
publicMemento createMemento() {
returnnew Memento(this.state);
}
//恢复一个备份
publicvoid restoreMemento(Memento _memento) {
this.setState(_memento.getState());
}
}
public class Caretaker {
//备忘录对象
privateMemento memento;
publicMemento getMemento() {
returnmemento;
}
publicvoid setMemento(Memento memento) {
this.memento= memento;
}
}
public class Client {
publicstatic void main(String[] args) {
//声明出主角
Boy boy = new Boy();
//声明出备忘录的管理者
Caretakercaretaker = new Caretaker();
//初始化当前状态
boy.setState("心情很棒!");
System.out.println("=====男孩现在的状态======");
System.out.println(boy.getState());
//需要记录下当前状态呀
caretaker.setMemento(boy.createMemento());
//男孩去追女孩,状态改变
boy.changeState();
System.out.println("\n=====男孩追女孩子后的状态======");
System.out.println(boy.getState());
//追女孩失败,恢复原状
boy.restoreMemento(caretaker.getMemento());
System.out.println("\n=====男孩恢复后的状态======");
System.out.println(boy.getState());
}
}
观察者模式
特点:
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
优点:
观察者和被观察者之间是抽象耦合,不管是增加观察者还是被观察者都非常容易扩展建立一套触发机制。根据单一职责原则,每个类的职责是单一的,通过观察者模式可以把各个单一的职责串联成真实世界的复杂的逻辑关系。
缺点:
开发效率和运行效率问题,一个被观察者,多个观察者,开发和调试就会比较复杂,而且在Java中消息的通知默认是顺序执行,一个观察者卡壳,会影响整体的执行效率。在这种情况下,一般考虑采用异步的方式。
使用场景:
①关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系
②事件多级触发场景。
③跨系统的消息交换场景,如消息队列的处理机制。
示例代码:
public abstract class AllyControlCenter {
protectedString allyName;
protectedArrayList players=new ArrayList();
publicvoid setAllyName(String allyName){
this.allyName=allyName;
}
publicString getAllyName(){
returnthis.allyName;
}
publicvoid join(Observer obs){
System.out.println(obs.getName()+"加入"+this.allyName+"战队!");
players.add(obs);
}
publicvoid quit(Observer obs){
System.out.println(obs.getName()+"退出"+this.allyName+"战队!");
players.remove(obs);
}
publicabstract void notifyObserver(String name);
}
public class ConcreteAllyControlCenterextends AllyControlCenter{
publicConcreteAllyControlCenter(String allyName){
System.out.println(allyName+"战队组建成功!");
System.out.println("--------------------");
this.allyName=allyName;
}
publicvoid notifyObserver(String name){
System.out.println(this.allyName+"战队紧急通知,盟友"+name+"遭受敌人攻击!");
//遍历观察者集合,调用每一个盟友(自己除外)的支援方法
for(Objectobs:players){
if(!((Observer)obs).getName().equalsIgnoreCase(name)){
((Observer)obs).help();
}
}
}
}
public interface Observer {
publicString getName();
publicvoid setName(String name);
publicvoid help();
publicvoid beAttacked(AllyControlCenter acc);
}
public class Player implements Observer{
privateString name;
publicPlayer(String name){
this.name=name;
}
publicvoid setName(String name){
this.name=name;
}
publicString getName(){
returnthis.name;
}
publicvoid help(){
System.out.println("坚持住,"+this.name+"来救你!");
}
//遭受攻击方法的实现,当遭受攻击时将调用战队控制中心类的通知方法notifyO()来通知盟友
publicvoid beAttacked(AllyControlCenter acc){
System.out.println(this.name+"被攻击!");
acc.notifyObserver(name);
}
}
public class Client {
publicstatic void main(String[] args){
AllyControlCenterallyControlCenter;
allyControlCenter=newConcreteAllyControlCenter("金庸群侠");
Observerplayer1,player2,player3,player4;
player1=newPlayer("杨过");
allyControlCenter.join(player1);
player2=newPlayer("令狐冲");
allyControlCenter.join(player2);
player3=newPlayer("张无忌");
allyControlCenter.join(player3);
player4=newPlayer("段誉");
allyControlCenter.join(player4);
player1.beAttacked(allyControlCenter);
}
}
状态模式
特点:
状态模式的核心是封装,状态的变更引起了行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。
优点:
①结构清晰,避免了过多的switch...case或者if...else语句的使用,避免了程序的复杂性,提高系统的可维护性
②遵循设计原则。很好地体现了开闭原则和单一职责原则,每个状态都是一个子类,你要增加状态就要增加子类,你要修改状态,你只修改一个子类就可以了。
③封装性非常好。这也是状态模式的基本要求,状态变换放置到类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。
缺点:
类膨胀。如果完全使用状态模式就会有太多的子类,不好管理。其实有很多方式可以解决这个状态问题,如在数据库中建立一个状态表,然后根据状态执行相应的操作,这个也不复杂。
使用场景:
①行为随状态改变而改变的场景。例如权限设计,人员的状态不同即使执行相同的行为结果也会不同,在这种情况下需要考虑使用状态模式。
②条件、分支判断语句的替代者。在程序中大量使用switch语句或者if判断语句会导致程序结构不清晰,逻辑混乱,使用状态模式可以很好地避免这一问题,它通过扩展子类实现了条件的判断处理
示例代码:
public abstract class LiftState {
//定义一个环境角色,也就是封装状态的变化引起的功能变化
protectedContext context;
publicvoid setContext(Context _context) {
this.context= _context;
}
//首先电梯门开启动作
publicabstract void open();
//电梯门有开启,那当然也就有关闭了
publicabstract void close();
//电梯要能上能下,运行起来
publicabstract void run();
//电梯还要能停下来
publicabstract void stop();
}
public class OpenningState extendsLiftState {
//开启当然可以关闭了,我就想测试一下电梯门开关功能
@Override
publicvoid close() {
//状态修改
super.context.setLiftState(Context.closeingState);
//动作委托为CloseState来执行
super.context.getLiftState().close();
}
//打开电梯门
@Override
publicvoid open() {
System.out.println("电梯门开启...");
}
//门开着时电梯就运行跑,这电梯,吓死你!
@Override
publicvoid run() {
//do nothing;
}
//开门还不停止?
publicvoid stop() {
//do nothing;
}
}
public class RunningState extends LiftState{
//电梯门关闭?这是肯定的
@Override
publicvoid close() {
//do nothing
}
//运行的时候开电梯门?你疯了!电梯不会给你开的
@Override
publicvoid open() {
//do nothing
}
//这是在运行状态下要实现的方法
@Override
publicvoid run() {
System.out.println("电梯上下运行...");
}
//这绝对是合理的,只运行不停止还有谁敢坐这个电梯?!估计只有上帝了
@Override
publicvoid stop() {
super.context.setLiftState(Context.stoppingState);//环境设置为停止状态
super.context.getLiftState().stop();
}
}
public class StoppingState extendsLiftState {
//停止状态关门?电梯门本来就是关着的!
@Override
publicvoid close() {
//do nothing;
}
//停止状态,开门,那是要的!
@Override
publicvoid open() {
super.context.setLiftState(Context.openningState);
super.context.getLiftState().open();
}
//停止状态再运行起来,正常得很
@Override
publicvoid run() {
super.context.setLiftState(Context.runningState);
super.context.getLiftState().run();
}
//停止状态是怎么发生的呢?当然是停止方法执行了
@Override
publicvoid stop() {
System.out.println("电梯停止了...");
}
}
public class ClosingState extends LiftState{
//电梯门关闭,这是关闭状态要实现的动作
@Override
publicvoid close() {
System.out.println("电梯门关闭...");
}
//电梯门关了再打开
@Override
publicvoid open() {
super.context.setLiftState(Context.openningState);// 置为敞门状态
super.context.getLiftState().open();
}
//电梯门关了就运行,这是再正常不过了
@Override
publicvoid run() {
super.context.setLiftState(Context.runningState);// 设置为运行状态
super.context.getLiftState().run();
}
//电梯门关着,我就不按楼层
@Override
publicvoid stop() {
super.context.setLiftState(Context.stoppingState);// 设置为停止状态
super.context.getLiftState().stop();
}
}
public class Context {
//定义出所有的电梯状态
publicfinal static OpenningState openningState = new OpenningState();
publicfinal static ClosingState closeingState = new ClosingState();
publicfinal static RunningState runningState = new RunningState();
publicfinal static StoppingState stoppingState = new StoppingState();
//不成文的规定:
//把状态对象声明为静态常量,有几个状态对象就声明几个静态常量。
//环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式。
//定义一个当前电梯状态
privateLiftState liftState;
publicLiftState getLiftState() {
returnliftState;
}
publicvoid setLiftState(LiftState liftState) {
this.liftState= liftState;
//把当前的环境通知到各个实现类中
this.liftState.setContext(this);
}
publicvoid open() {
this.liftState.open();
}
publicvoid close() {
this.liftState.close();
}
publicvoid run() {
this.liftState.run();
}
publicvoid stop() {
this.liftState.stop();
}
}
public class Client {
publicstatic void main(String[] args) {
Contextcontext = new Context();
context.setLiftState(newClosingState());
context.open();
context.close();
context.run();
context.stop();
}
}
策略模式:
特点:
定义一组算法,将每个算法都封装起来,并且使它们之间可以互换
优点:
①算法可以自由切换,只要实现抽象策略,它就成为策略家族的一个成员,避免使用多重条件判断。使用策略模式后,可以由其他模块决定采用何种策略,策略家族对外提供的访问接口就是封装类,简化了操作,同时避免了条件语句判断。
②扩展性良好。在现有的系统中增加一个策略太容易了,只要实现接口就可以了,其他都不用修改,类似于一个可反复拆卸的插件,这大大地符合了OCP原则。
缺点:
①每一个策略都是一个类,复用的可能性很小,类数量增多。
②所有的策略类都需要对外暴露。上层模块必须知道有哪些策略,然后才能决定使用哪一个策略。
适用场景:
①多个类只有在算法或行为上稍有不同的场景。
②算法需要自由切换的场景。
③需要屏蔽算法规则的场景。
策略模式是一个非常简单的模式。它在项目中使用得非常多,但它单独使用的地方就比较少了,因为它有致命缺陷:所有的策略都需要暴露出去,这样才方便客户端决定使用哪一个策略。在实际项目中,我们一般通过工厂方法模式来实现策略类的声明。
示例代码:
public interface IStrategy {
//每个锦囊妙计都是一个可执行的算法
publicvoid operate();
}
public class GivenGreenLight implementsIStrategy {
publicvoid operate() {
System.out.println("求吴国太开绿灯,放行!");
}
}
public class BackDoor implements IStrategy{
publicvoid operate() {
System.out.println("找乔国老帮忙,让吴国太给孙权施加压力");
}
}
public class BlockEnemy implementsIStrategy {
publicvoid operate() {
System.out.println("孙夫人断后,挡住追兵");
}
}
public class Context {
//构造函数,你要使用哪个妙计
privateIStrategy straegy;
publicContext(IStrategy strategy) {
this.straegy= strategy;
}
//使用计谋了,看我出招了
publicvoid operate() {
this.straegy.operate();
}
}
public class ZhaoYun {
//赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计
publicstatic void main(String[] args) {
Contextcontext;
//刚刚到吴国的时候拆第一个
System.out.println("---刚刚到吴国的时候拆第一个---");
context= new Context(new BackDoor()); // 拿到妙计
context.operate();// 拆开执行
//刘备乐不思蜀了,拆第二个了
System.out.println("---刘备乐不思蜀了,拆第二个了---");
context= new Context(new GivenGreenLight());
context.operate();// 执行了第二个锦囊
//孙权的小兵追来了,咋办?拆第三个
System.out.println("---孙权的小兵追来了,咋办?拆第三个---");
context= new Context(new BlockEnemy());
context.operate();// 孙夫人退兵
}
}
模板方法模式
特点:
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。仅仅使用了Java的继承机制,但它是一个应用非常广泛的模式。
优点:
①封装不变部分,扩展可变部分。
②行为由父类控制,子类实现。
③提取公共部分代码,便于维护。
缺点:
需要为每一个基本方法的不同实现提供一个子类,如果父类中可变的基本方法太多,将会导致类的个数增加,系统更加庞大,设计也更加抽象。
适用场景:
①多个子类有公有的方法,并且逻辑基本相同时。
②重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
示例代码:
public abstract class HummerModel {
publicabstract void start();
publicabstract void stop();
publicabstract void alarm();
publicabstract void engineBoom();
publicvoid run() {
//先发动汽车
this.start();
//引擎开始轰鸣
this.engineBoom();
//然后就开始跑了
this.alarm();
//到达目的地就停车
this.stop();
}
}
public class HummerH1Model extendsHummerModel {
//H1型号的悍马车鸣笛
publicvoid alarm() {
System.out.println("悍马H1鸣笛...");
}
//引擎轰鸣声
publicvoid engineBoom() {
System.out.println("悍马H1引擎声音是这样的...");
}
//汽车发动
publicvoid start() {
System.out.println("悍马H1发动...");
}
//停车
publicvoid stop() {
System.out.println("悍马H1停车...");
}
}
public class HummerH2Model extendsHummerModel {
//H2型号的悍马车鸣笛
publicvoid alarm() {
System.out.println("悍马H2鸣笛...");
}
//引擎轰鸣声
publicvoid engineBoom() {
System.out.println("悍马H2引擎声音是这样在...");
}
//汽车发动
publicvoid start() {
System.out.println("悍马H2发动...");
}
//停车
publicvoid stop() {
System.out.println("悍马H2停车...");
}
}
public class Client {
publicstatic void main(String[] args) {
HummerModelh1 = new HummerH1Model();
h1.run();
HummerModelh2 = new HummerH2Model();
h2.run();
}
}
访问者模式
特点:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
优点:
①符合单一职责原则。具体元素角色也就是Employee抽象类的两个子类负责数据的加载,而Visitor类则负责报表的展现,两个不同的职责非常明确地分离开来,各自演绎变化。
②优秀的扩展性。由于职责分开,继续增加对数据的操作是非常快捷的,例如,现在要增加一份给大老板的报表,这份报表格式又有所不同,直接在Visitor中增加一个方法,传递数据后进行整理打印。灵活性非常高.
缺点:
①具体元素对访问者公布细节。访问者要访问一个类就必然要求这个类公布一些方法和数据,也就是说访问者关注了其他类的内部细节。
②具体元素变更比较困难。具体元素角色的增加、删除、修改都是比较困难的。
③违背了依赖倒置转原则。访问者依赖的是具体元素,而不是抽象元素,这破坏了依赖倒置原则,特别是在面向对象的编程中,抛弃了对接口的依赖,而直接依赖实现类,扩展比较难。
适用场景:
①一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作,也就说是用迭代器模式已经不能胜任的情景。
②需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。
③业务规则要求遍历多个不同的对象。
示例代码:
public abstract class Employee {
publicfinal static int MALE = 0; // 0代表是男性
publicfinal static int FEMALE = 1; // 1代表是女性
//甭管是谁,都有工资
privateString name;
//只要是员工那就有薪水
privateint salary;
//性别很重要
privateint sex;
//以下是简单的getter/setter
publicString getName() {
returnname;
}
publicvoid setName(String name) {
this.name= name;
}
publicint getSalary() {
returnsalary;
}
publicvoid setSalary(int salary) {
this.salary= salary;
}
publicint getSex() {
returnsex;
}
publicvoid setSex(int sex) {
this.sex= sex;
}
//我允许一个访问者访问
publicabstract void accept(IVisitor visitor);
}
public class Manager extends Employee {
//这类人物的职责非常明确:业绩
privateString performance;
publicString getPerformance() {
returnperformance;
}
publicvoid setPerformance(String performance) {
this.performance= performance;
}
//部门经理允许访问者访问
@Override
publicvoid accept(IVisitor visitor) {
visitor.visit(this);
}
}
public class CommonEmployee extendsEmployee {
privateString job;
publicString getJob() {
returnjob;
}
publicvoid setJob(String job) {
this.job= job;
}
//我允许访问者访问
@Override
publicvoid accept(IVisitor visitor) {
visitor.visit(this);
}
}
public interface IVisitor {
//首先,定义我可以访问普通员工
publicvoid visit(CommonEmployee commonEmployee);
//其次,定义我还可以访问部门经理
publicvoid visit(Manager manager);
}
public class Visitor implements IVisitor {
//访问普通员工,打印出报表
publicvoid visit(CommonEmployee commonEmployee) {
System.out.println(this.getCommonEmployee(commonEmployee));
}
//访问部门经理,打印出报表
publicvoid visit(Manager manager) {
System.out.println(this.getManagerInfo(manager));
}
//组装出基本信息
privateString getBasicInfo(Employee employee) {
Stringinfo = "姓名:" + employee.getName() +"\t";
info= info + "性别:" + (employee.getSex() ==Employee.FEMALE ? "女" : "男") + "\t";
info= info + "薪水:" + employee.getSalary() +"\t";
returninfo;
}
//组装出部门经理的信息
privateString getManagerInfo(Manager manager) {
StringbasicInfo = this.getBasicInfo(manager);
StringotherInfo = "业绩:" + manager.getPerformance()+ "\t";
returnbasicInfo + otherInfo;
}
//组装出普通员工信息
privateString getCommonEmployee(CommonEmployee commonEmployee) {
StringbasicInfo = this.getBasicInfo(commonEmployee);
StringotherInfo = "工作:" + commonEmployee.getJob() +"\t";
returnbasicInfo + otherInfo;
}
}
public class Client {
publicstatic void main(String[] args) {
for(Employee emp : mockEmployee()) {
emp.accept(newVisitor());
}
}
//模拟出公司的人员情况,我们可以想象这个数据是通过持久层传递过来的
publicstatic List mockEmployee() {
ListempList = new ArrayList();
//产生张三这个员工
CommonEmployeezhangSan = new CommonEmployee();
zhangSan.setJob("编写Java程序,绝对的蓝领、苦工加搬运工");
zhangSan.setName("张三");
zhangSan.setSalary(1800);
zhangSan.setSex(Employee.MALE);
empList.add(zhangSan);
//产生李四这个员工
CommonEmployeeliSi = new CommonEmployee();
liSi.setJob("页面美工,审美素质太不流行了!");
liSi.setName("李四");
liSi.setSalary(1900);
liSi.setSex(Employee.FEMALE);
empList.add(liSi);
//再产生一个经理
ManagerwangWu = new Manager();
wangWu.setName("王五");
wangWu.setPerformance("基本上是负值,但是我会拍马屁呀");
wangWu.setSalary(18750);
wangWu.setSex(Employee.MALE);
empList.add(wangWu);
returnempList;
}
}