实验一 工厂模式的应用
有一个OEM制造商代理做HP笔记本电脑(Laptop),后来该制造商得到了更多的品牌笔记本电脑的订单Acer,Lenovo,Dell,该OEM商发现,如果一次同时做很多个牌子的本本,有些不利于管理。利用工厂模式改善设计,用JAVA语言实现 (或C#控制台应用程序实现)该OEM制造商的工厂模式。绘制该模式的UML图。
【模式代码(JAVA语言实现)】
public class FactoryMethod {
public static void main(String[] args) {
Computer c = null;
Factory f = null;
f = new DellFactory();
c = f.getComputerType();
c.ComputerType();
f = new LenovoFactory();
c = f.getComputerType();
c.ComputerType();
f = new AcerFactory();
c = f.getComputerType();
c.ComputerType();
}
}
interface Factory{
Computer getComputerType();
}
class DellFactory implements Factory{
@Override
public Computer getComputerType() {
return new Dell();
}
}
class AcerFactory implements Factory{
@Override
public Computer getComputerType() {
return new Acer();
}
}
class LenovoFactory implements Factory{
@Override
public Computer getComputerType() {
return new Lenovo();
}
}
interface Computer{
public void ComputerType();
}
class Dell implements Computer{
@Override
public void ComputerType() {
System.out.println("Dell Computer");
}
}
class Acer implements Computer{
@Override
public void ComputerType() {
System.out.println("Acer Computer");
}
}
class Lenovo implements Computer{
@Override
public void ComputerType() {
System.out.println("Lenovo Computer");
}
}
实验二 抽象工厂模式的应用
【模式UML图】
麦当劳(McDonalds)和肯德基(KFC)快餐店都经营汉堡(Hamburg)和可乐(Cole),用JAVA语言实现(C#控制台应用程序实现)这两个快餐店经营产品的抽象工厂模式。绘制该模式的UML图。
【模式代码】
public class AbstractFactoryTest {
public static void main(String[] args) {
Hamburg h = null;
Cola c = null;
AbstractFactory af = null;
af = new MDNFactory();
h = af.createHamburg();
c = af.createCola();
h.getHumburg();
c.getCola();
af = new KDJFactory();
h = af.createHamburg();
c = af.createCola();
h.getHumburg();
c.getCola();
}
}
interface AbstractFactory{
Hamburg createHamburg();
Cola createCola();
}
class MDNFactory implements AbstractFactory{
@Override
public Hamburg createHamburg() {
return new MDNHamburg();
}
@Override
public Cola createCola() {
return new MDNCola();
}
}
class KDJFactory implements AbstractFactory{
@Override
public Hamburg createHamburg() {
return new KDJHamburg();
}
@Override
public Cola createCola() {
return new KDJCola();
}
}
interface Hamburg{
void getHumburg();
}
class MDNHamburg implements Hamburg{
@Override
public void getHumburg() {
System.out.println("MDNHamburg");
}
}
class KDJHamburg implements Hamburg{
@Override
public void getHumburg() {
System.out.println("KDJHamburg");
}
}
interface Cola{
void getCola();
}
class MDNCola implements Cola{
@Override
public void getCola() {
System.out.println("MDNCola");
}
}
class KDJCola implements Cola{
@Override
public void getCola() {
System.out.println("KDJCola");
}
}
【运行截图】
实验三 建造者模式的应用
实例:KFC套餐
建造者模式可以用于描述KFC如何创建套餐:套餐是一个复杂对象,它一般包含主食(如汉堡、鸡肉卷等)和饮料(如果汁、可乐等)等组成部分,不同的套餐有不同的组成部分,而KFC的服务员可以根据顾客的要求,一步一步装配这些组成部分,构造一份完整的套餐,然后返回给顾客。利用建造者模式设计,用JAVA语言实现 (或C#控制台应用程序实现)。绘制该模式的UML图。
【模式UML图】
【模式代码(JAVA语言实现)】
SetMeal.java:
public class SetMeal {
String StapleFood; //主食
String Dringks; //饮料
public String getStapleFood() {
return StapleFood;
}
public void setStapleFood(String stapleFood) {
StapleFood = stapleFood;
}
public String getDringks() {
return Dringks;
}
public void setDringks(String dringks) {
Dringks = dringks;
}
}
SetMealBuilder.java:
public abstract class SetMealBuilder {
SetMeal setMeal = new SetMeal();
public abstract void createStapleFood();
public abstract void createDrinks();
public SetMeal getSetMeal() {
return setMeal;
}
}
SetMealBuilderA.java:
public class SetMealBuilderA extends SetMealBuilder{
@Override
public void createStapleFood() {
setMeal.setStapleFood("Hamburger");
}
@Override
public void createDrinks() {
setMeal.setDringks("juice");
}
}
SetMealBuilderB.java:
public class SetMealBuilderB extends SetMealBuilder{
@Override
public void createStapleFood() {
setMeal.setStapleFood("ChickenRolls");
}
@Override
public void createDrinks() {
setMeal.setDringks("Cola");
}
}
Director.java:
public class Director {
private SetMealBuilder setMealBuilder;
public Director(SetMealBuilder setMealBuilder) {
this.setMealBuilder = setMealBuilder;
}
public SetMeal construct() {
//准备主食
setMealBuilder.createStapleFood();
//准备饮料
setMealBuilder.createDrinks();
//返回一个套餐
return setMealBuilder.getSetMeal();
}
}
Client.java:
public class Client {
public static void main(String[] args) {
System.out.println("---------KFC套餐选择---------");
//建造套餐A
SetMealBuilder setMealABuilder = new SetMealBuilderA();
Director kfcDirector = new Director(setMealABuilder);
SetMeal kfcSetMealA = kfcDirector.construct();
System.out.println("套餐A:");
System.out.println("主食:"+kfcSetMealA.getStapleFood()+" 饮料:"+kfcSetMealA.getDringks());
//建造套餐B
SetMealBuilder setMealBBuilder = new SetMealBuilderB();
kfcDirector = new Director(setMealBBuilder);
SetMeal kfcSetMealB = kfcDirector.construct();
System.out.println("套餐B:");
System.out.println("主食:"+kfcSetMealB.getStapleFood()+" 饮料:"+kfcSetMealB.getDringks());
}
}
通过本次实验,学会了使用建造者模式。建造者模式的适用性如下:
当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
当构造过程必须允许被构造的对象有不同表示时。
需要生成的对象具有复杂的内部结构。
需要生成的对象内部属性本身相互依赖。
实验四 单例模式的应用
在操作系统中,打印池(Print Spooler)是一个用于管理打印任务的应用程序,通过打印池用户可以删除、中止或者改变打印任务的优先级,在一个系统中只允许运行一个打印池对象,如果重复创建打印池则抛出异常。现使用单例模式来模拟实现打印池的设计。用JAVA语言实现(C#控制台应用程序实现)该模式。绘制该模式的UML图。
【模式UML图】
【模式代码】
class PrintSpoolerSingleton {
private static PrintSpoolerSingleton instance = null;
// 私有化构造方法,外界无法通过new创建此类的实例
private PrintSpoolerSingleton() {
}
;
//静态工厂方法 synchronized 同步方法加锁,保证每次只有一个线程进入
public static synchronized PrintSpoolerSingleton getInstance() {
if (instance == null) {
System.out.println("创建打印池!");
instance = new PrintSpoolerSingleton();
} else {
System.out.println("打印池正在工作中!");
}
return instance;
}
}
public class Singleton {
public static void main(String a[]) {
PrintSpoolerSingleton ps1 = null, ps2 = null;
ps1.getInstance();
ps2.getInstance();
}
}
【运行截图】
【实验小结】
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式主要适用于以下情况:
(1)资源共享的情况下,避免由于资源操作时导致的性能问题或损耗等。如上述中的日志文件,应用配置。
(2)控制资源的情况下,方便资源之间的互相通信。如线程池等。
实验五 组合模式的应用
在水果盘(Plate)中有一些水果,如苹果(Apple)、香蕉(Banana)、梨子(Pear),当然大水果盘中还可以有小水果盘,现需要对盘中的水果进行遍历(吃),当然如果对一个水果盘执行“吃”方法,实际上就是吃其中的水果。使用组合模式模拟该场景。
利用组合者模式设计,用JAVA语言实现 (或C#控制台应用程序实现)。绘制该模式的UML图。
【模式UML图】
【模式代码(JAVA语言实现)】
public abstract class MyElement
{
public abstract void eat();
}
public class Pear extends MyElement
{
public void eat()
{
System.out.println("吃梨子!");
}
}
public class Banana extends MyElement
{
public void eat()
{
System.out.println("吃香蕉!");
}
}
public class Apple extends MyElement
{
public void eat()
{
System.out.println("吃苹果!");
}
}
public class Client
{
public static void main(String a[])
{
MyElement obj1,obj2,obj3,obj4,obj5;
Plate plate1,plate2,plate3;
obj1=new Apple();
obj2=new Pear();
plate1=new Plate();
plate1.add(obj1);
plate1.add(obj2);
obj3=new Banana();
obj4=new Banana();
plate2=new Plate();
plate2.add(obj3);
plate2.add(obj4);
obj5=new Apple();
plate3=new Plate();
plate3.add(plate1);
plate3.add(plate2);
plate3.add(obj5);
plate3.eat();
}
}
import java.util.*;
public class Plate extends MyElement
{
private ArrayList list=new ArrayList();
public void add(MyElement element)
{
list.add(element);
}
public void delete(MyElement element)
{
list.remove(element);
}
public void eat()
{
for(Object object:list)
{
((MyElement)object).eat();
}
}
}
【实验小结】
组合(Composite Pattern)模式的定义:有时又叫作整体-部分(Part-Whole)模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性,属于结构型设计模式。
通过本次实验,学会了使用组合模式。组合模式的适用性如下:
在需要表示一个对象整体与部分的层次结构的场合。
要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合。
实验六 适配器模式的应用
加密适配器
某系统需要提供一个加密模块,将用户信息(如密码等机密信息)加密之后再存储在数据库中,系统已经定义好了数据库操作类。为了提高开发效率,现需要重用已有的加密算法,这些算法封装在一些由第三方提供的类中,有些甚至没有源代码。使用适配器模式设计该加密模块,实现在不修改现有类的基础上重用第三方加密方法。
现使用适配器模式来模拟实现以上的设计。用JAVA语言实现(C#控制台应用程序实现)该模式。绘制该模式的UML图。
【模式UML图】
【模式代码】
public abstract class DataOperation {
public abstract String doEncrypt(String ps);
}
public class CipherAdapter extends DataOperation {
private Caesar cipher;
public CipherAdapter() {
cipher=new Caesar();
}
public String doEncrypt(String ps) {
return cipher.doEncrypt(ps);
}
}
public class Caesar {
public String doEncrypt(String ps) {
return "原来加密方法加密之后的"+ps;
}
}
public class NewCipherAdapter extends DataOperation {
private NewCipher cipher;
public NewCipherAdapter() {
cipher=new NewCipher();
}
public String doEncrypt(String ps) {
return cipher.doEncrypt(ps);
}
}
public class NewCipher {
public String doEncrypt(String ps) {
return "新加密方法加密之后的"+ps;
}
}
public class Client {
public static void main(String[] args) {
String s1 = "123456";
String s2 = "";
DataOperation data = null;
data = new CipherAdapter();
s2 = data.doEncrypt(s1);
System.out.println(s2);
data = new NewCipherAdapter();
s2 = data.doEncrypt(s1);
System.out.println(s2);
}
}
实验七 外观模式的应用
电源总开关
现在考察一个电源总开关的例子,以便进一步说明外观模式。为了使用方便,一个电源总开关可以控制四盏灯、一个风扇、一台空调和一台电视机的启动和关闭。通过该电源总开关可以同时控制上述所有电器设备,使用外观模式设计该系统。
用JAVA语言实现 (或C#控制台应用程序实现)。绘制该模式的UML图。
【模式UML图】
【模式代码(JAVA语言实现)】
package 外观模式2;
//外观角色
public class GeneralSwitchFaceade {
private Light[] lights =new Light[4];
private Fan fan;
private AirConditssioner ac;
private Televisions tv;
public GeneralSwitchFaceade(){
lights[0] = new Light("左前");
lights[1] = new Light("右前");
lights[2] = new Light("左后") ;
lights[3] = new Light("右后") ;
ac = new AirConditssioner();
fan = new Fan();
tv = new Televisions();
}
public void on()
{
lights[0].on();
lights[1].on();
lights[2].on();
lights[3].on();
ac.on();
fan.on();
tv.on();
}
public void off() {
lights[0].off();
lights[1].off();
lights[2].off();
lights[3].off();
ac.off();
fan.off();
tv.off();
}
}
//子系统角色
public class AirConditssioner {
public void on(){
System.out.println("空调打开");
}
public void off(){
System.out.println("空调关闭");
}
}
public class Fan {
public void on(){
System.out.println("风扇打开");
}
public void off(){
System.out.println("风扇关闭");
}
}
//子系统角色
public class Light {
String position;
public Light(String position){
this.position = position;
}
public void on(){
System.out.println("灯"+position+"打开");
}
public void off(){
System.out.println("灯"+position+"关闭");
}
}
//子系统角色
public class Televisions {
public void on(){
System.out.println("电视打开");
}
public void off(){
System.out.println("电视关闭");
}
}
public class Switch {
public static void main(String[] args) {
GeneralSwitchFaceade gsf = new GeneralSwitchFaceade();
gsf.on();
System.out.println("-----------------------------");
gsf.off();
}
}
【实验小结】
通过本次实验,学会了使用外观模式。
定义为:为子系统中的一组接口提供一个一致的界面。此模式定义了一个高层接口,使得这一子系统更加容易使用。
外观模式的适用性如下:
设计初期阶段,应该有意识的将不同层分离,层与层之间建立外观模式。
开发阶段,子系统越来越复杂,增加外观模式提供一个简单的调用接口。
维护一个大型遗留系统的时候,可能这个系统已经非常难以维护和扩展,但又包含非常重要的功能,为其开发一个外观类,以便新系统与其交互。
适配器模式主要适用于以下情况:
1)统需要使用一些现有的类,而这些类的接口(如方法名)不符合系统的需要,甚至没有这些类的源代码。
2)创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
实验八 桥接模式的应用
模拟毛笔
现需要提供大中小3种型号的画笔,能够绘制5种不同颜色,如果使用蜡笔,我们需要准备3*5=15支蜡笔,也就是说必须准备15个具体的蜡笔类。而如果使用毛笔的话,只需要3种型号的毛笔,外加5个颜料盒,用3+5=8个类就可以实现15支蜡笔的功能。请使用桥接模式来模拟毛笔的使用过程。
用JAVA语言实现(C#控制台应用程序实现)该模式。绘制该模式的UML图。
【模式UML图】
【代码】
public class BigPen extends Pen {
public void draw(String name)
{
String penType="大号毛笔绘制";
this.color.bepaint(penType,name);
}
}
public class Black implements Color{
public void bepaint(String penType , String name){
System.out.println(penType + "黑色的"+ name + ".");
}
}
public class Blue implements Color{
public void bepaint(String penType , String name){
System.out.println(penType + "黑色的"+ name + ".");
}
}
public class Green implements Color{
public void bepaint(String penType , String name){
System.out.println(penType + "绿色的"+ name + ".");
}
}
public class Red implements Color{
public void bepaint(String penType , String name){
System.out.println(penType + "红色的"+ name + ".");
}
}
public class White implements Color{
public void bepaint(String penType , String name){
System.out.println(penType + "白色的"+ name + ".");
}
}
public interface Color {
void bepaint(String penType,String name);
}
public class Client {
public static void main(String a[])
{
Color color;
Pen pen;
color=(Color)XMLUtilPen.getBean("color");
pen=(Pen)XMLUtilPen.getBean("pen");
pen.setColor(color);
pen.draw("鲜花");
}
}
public abstract class Pen {
protected Color color;
public void setColor(Color color)
{
this.color=color;
}
public abstract void draw(String name);
}
public class BigPen extends Pen {
public void draw(String name)
{
String penType="大号毛笔绘制";
this.color.bepaint(penType,name);
}
}
public class SmallPen extends Pen{
public void draw(String name)
{
String penType="小号毛笔绘制";
this.color.bepaint(penType,name);
}
}
import java.io.File;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
import org.w3c.dom.NodeList;
public class XMLUtilPen {
public static Object getBean(String args)
{
try
{
//创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("src/casepen/configPen.xml"));
NodeList nl=null;
Node classNode=null;
String cName=null;
nl = doc.getElementsByTagName("className");
if(args.equals("color"))
{
//获取包含类名的文本节点
classNode=nl.item(0).getFirstChild();
}
else if(args.equals("pen"))
{
//获取包含类名的文本节点
classNode=nl.item(1).getFirstChild();
}
cName=classNode.getNodeValue();
//通过类名生成实例对象并将其返回
Class c=Class.forName("casepen."+cName);
Object obj=c.newInstance();
return obj;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
}
config.xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<className>Blue</className>
<className>SmallPen</className>
</config>
【运行截图】
四、心得体会:
桥接模式主要适用于以下情况:
1)如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
2)对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
3)一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
实验九 迭代器模式的应用
电视机遥控器就是一个迭代器的实例,通过它可以实现对电视机频道集合的遍历操作,迭代器模式模拟电视机遥控器的实现。
【模式代码(JAVA语言实现)】
TVIterator.java
public interface TVIterator {
public boolean isFirst();
public boolean isLast();
public void next();
public void previous();
public void setChannel(int i);
public Object currentChannel();
}
Television.java
public interface Television {
public TVIterator createIterator();
}
TCLTelevision.java
public class TCLTelevision implements Television {
Object[] obj= {"cctv1","cctv2","cctv3","cctv4","cctv5","cctv6","cctv7"};
@Override
public TVIterator createIterator() {
// TODO Auto-generated method stub
return new TCLIterator();
}
class TCLIterator implements TVIterator{
private int currentIndex=0;
@Override
public boolean isFirst() {
if(currentIndex==0) {
return true;
}else {
return false;
}
}
@Override
public boolean isLast() {
if(currentIndex==obj.length) {
return true;
}
return false;
}
@Override
public void next() {
// TODO Auto-generated method stub
if(currentIndex<obj.length) {
currentIndex++;
}else {
currentIndex=0;
}
}
@Override
public void previous() {
// TODO Auto-generated method stub
if(currentIndex<obj.length) {
currentIndex--;
}else {
currentIndex=obj.length-1;
}
}
@Override
public void setChannel(int i) {
// TODO Auto-generated method stub
currentIndex=i;
}
@Override
public Object currentChannel() {
// TODO Auto-generated method stub
return obj[currentIndex];
}
}
}
Client.java
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
Television tv;
tv=new TCLTelevision();
TVIterator it=tv.createIterator();
while(!it.isLast()) {
System.out.println(it.currentChannel().toString());
it.next();
}
System.out.println("^^^^^^^^^^^^^^^^^^^^^^");
it.setChannel(4);
System.out.println(it.currentChannel().toString());
System.out.println("^^^^^^^^^^^^^^^^^^^^^^");
}
}
四、心得体会:
迭代器模式(Iterator):
迭代器模式允许你访问一个数据项序列中的所有元素,而无须关心序列是什么类型(数组、链表、列表或任何其他类型)。它能有效地构建一个数据管道,经过一系列不同的转换或过滤后再从管道的另一端出来。迭代器模式就是提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示。
通过本次实验,学会了使用迭代器模式。迭代器模式的适用性如下:
当集合背后为复杂的数据结构,且你希望对客户端隐藏其复杂性时(出于使用便利性或安全性的考虑),可以使用迭代器。
可以减少程序中重复的遍历代码。
如果你希望代码能够遍历不同的甚至是无法预知的数据结构,可以使用迭代器。
实验十 访问者模式的应用
顾客在超市中将选择的商品,如苹果、图书等放在购物车中,然后到收银员处付款。在购物过程中,顾客需要对这些商品进行访问,以便确认这些商品的质量,之后收银员计算价格时也需要访问购物车内顾客所选择的商品。此时,购物车作为一个ObjectStructure(对象结构)用于存储各种类型的商品,而顾客和收银员作为访问这些商品的访问者,他们需要对商品进行检查和计价。不同类型的商品其访问形式也可能不同,如苹果需要过秤之后再计价,而图书不需要。使用访问者模式来设计该购物过程。
现使用访问者模式设计该购物过程。
用JAVA语言实现(C#控制台应用程序实现)该模式。绘制该模式的UML图。
【模式UML图】
【模式代码】
public abstract class Visitor {
protected String name;
public void setName(String name)
{
this.name=name;
}
public abstract void visit(Apple apple);
public abstract void visit(Book book);
}
class Customer extends Visitor{
public void visit(Apple apple)
{
System.out.println("顾客" + name + "选苹果。");
}
public void visit(Book book)
{
System.out.println("顾客" + name + "买书。");
}
}
interface Product {
void accept(Visitor visitor);
}
class Apple implements Product{
public void accept(Visitor visitor)
{
visitor.visit(this);
}
}
class Book implements Product{
public void accept(Visitor visitor)
{
visitor.visit(this);
}
}
public class Client {
public static void main(String a[])
{
Product b1=new Book();
Product b2=new Book();
Product a1=new Apple();
Visitor visitor;
BuyBasket basket=new BuyBasket();
basket.addProduct(b1);
basket.addProduct(b2);
basket.addProduct(a1);
visitor=(Visitor)XMLUtil.getBean();
visitor.setName("张三");
basket.accept(visitor);
}
}
public class Saler extends Visitor{
public void visit(Apple apple)
{
System.out.println("收银员" + name + "给苹果过秤,然后计算其价格。");
}
public void visit(Book book)
{
System.out.println("收银员" + name + "直接计算书的价格。");
}
}
public class BuyBasket {
private ArrayList list=new ArrayList();
public void accept(Visitor visitor)
{
Iterator i=list.iterator();
while(i.hasNext())
{
((Product)i.next()).accept(visitor);
}
}
public void addProduct(Product product)
{
list.add(product);
}
public void removeProduct(Product product)
{
list.remove(product);
}
}
import java.io.File;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
public class XMLUtil {
public static Object getBean()
{
try
{
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("src/Visitor/config.xml"));
NodeList nl = doc.getElementsByTagName("className");
Node classNode=nl.item(0).getFirstChild();
String cName=classNode.getNodeValue();
Class c=Class.forName("Visitor." + cName);
Object obj=c.newInstance();
return obj;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
}
Config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<className>Saler</className>
</config>
Config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<className>Customer</className>
</config>
二:
【实验小结】
访问者模式(Visitor Pattern):表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。
访问者模式的目的是封装一些施加于某种对象结构的元素之上的操作,一旦这些操作需要修改的话,接受这个操作的对象结构可以保持不变。为不同类型的元素提供多种访问操作方式,且可以在不修改原有系统的情况下增加新的操作方式。
访问者模式主要适用于以下情况:
一个对象结构包含很多类型的对象,希望对这些对象实施一些依赖其具体类型的操作。在访问者中针对每一种具体的类型都提供了一个访问操作,不同类型的对象可以有不同的访问操作。
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。访问者模式使得我们可以将相关的访问操作集中起来定义在访问者类中,对象结构可以被多个不同的访问者类所使用,将对象本身与对象的访问操作分离。
对象结构中元素对应的类很少改变,但经常需要在此对象结构上定义新的操作
实验十一 命令模式的应用
电视机是请求的接收者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应电视机的不同操作。抽象命令角色由一个命令接口来扮演,有三个具体的命令类实现了抽象命令接口,这三个具体命令类分别代表三种操作:打开电视机、关闭电视机和切换频道。显然,电视机遥控器就是一个典型的命令模式应用实例。
用JAVA语言实现 (或C#控制台应用程序实现)电视机遥控器的命令模式。绘制该模式的UML图。
【模式代码(JAVA语言实现)】
Command.java
public abstract class Command {
public abstract void execute();
}
Televlsion.java
public class Televlsion {
public void open() {
System.out.println("打开电视机。。。。");
}
public void close() {
System.out.println("关闭电视机。。。。");
}
public void change() {
System.out.println("换台。。。。");
}
}
TVOpenCommand.java
public class TVOpenCommand extends Command {
private Televlsion tv=new Televlsion();
@Override
public void execute() {
// TODO Auto-generated method stub
tv.open();
}
}
TVCloseCommand.java
public class TVCloseCommand extends Command {
private Televlsion tv=new Televlsion();
@Override
public void execute() {
// TODO Auto-generated method stub
tv.close();
}
}
TVChangeCommand.java
public class TVChangeCommand extends Command {
private Televlsion tv=new Televlsion();
@Override
public void execute() {
// TODO Auto-generated method stub
tv.change();
}
}
Controller.java
public class Controller {
private Command command;
public Controller(Command command) {
this.command=command;
}
public void function() {
command.execute();
}
}
Client.java
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
Command cmd,cmd2,cmd3;
//打开电视机
cmd=new TVOpenCommand();
Controller c1=new Controller(cmd);
c1.function();
//关闭电视机
cmd2 = new TVCloseCommand();
Controller c2=new Controller(cmd2);
c2.function();
//换台
cmd3=new TVChangeCommand();
Controller c3=new Controller(cmd3);
c3.function();
}
}
【运行截图】
【实验小结】
Command 命令模式 - 行为模式 (命令模式又称为动作(Action)模式或事务(Transaction)模式。)
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤消的操作。命令模式又称为动作(Action)模式或事务(Transaction)模式。
通过本次实验,学会了使用命令方法模式。命令方法模式的适用性如下:
(1)系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
(2)系统需要在不同的时间指定请求、将请求排队和执行请求。
(3)系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
(4)系统需要将一组操作组合在一起,即支持宏命令。
实验十二 中介者模式的应用
某论坛系统欲增加一个虚拟聊天室,允许论坛会员通过该聊天室进行信息交流,普通会员(CommonMember)可以给其他会员发送文本信息,钻石会员(DiamondMember)既可以给其他会员发送文本信息,还可以发送图片信息。该聊天室可以对不雅字符进行过滤,如“日”等字符;还可以对发送的图片大小进行控制。用中介者模式设计该虚拟聊天室。
用JAVA语言实现(C#控制台应用程序实现)中介者模式。绘制该模式的UML图。
【模式UML图】
【模式代码】
public abstract class Colleague
{
protected Mediator mediator;
protected String name;
public Colleague(){}
public Colleague(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Mediator getMediator() {
return mediator;
}
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public void setName(String name) {
this.name = name;
}
public abstract void sendText(String to,String message);
public abstract void sendImage(String to,String image);
public void receiveText(String sender,String text)
{
System.out.println(sender + "发送文本给" + this.name + "\n内容为:" + text);
}
public void receiveImage(String sender,String image)
{
System.out.println(sender+ "发送图片给" + this.name + "\n内容为:" + image);
}
}
public class CommonMember extends Colleague {
public CommonMember(String name) {
super(name);
}
@Override
public void sendText(String receiver, String text) {
mediator.sendText(name,receiver,text);
}
@Override
public void sendImage(String receiver, String image) {
System.out.println("普通会员不能发送图片!");
}
}
public class DiamondMember extends Colleague {
public DiamondMember(String name) {
super(name);
}
@Override
public void sendText(String receiver, String text) {
mediator.sendText(name,receiver,text);
}
@Override
public void sendImage(String receiver, String image) {
mediator.sendImage(name,receiver,image);
}
}
public abstract class Mediator {
protected Map<String,Object> colleagues=new HashMap<String,Object>();
public void register(Colleague colleague)
{
colleagues.put(colleague.getName(),colleague);
colleague.setMediator(this);
}
public abstract void sendText(String sender,String receiver,String text);
public abstract void sendImage(String sender,String receiver,String image);
}
public class ConcreteMediator extends Mediator {
@Override
public void sendText(String sender, String receiver, String text) {
Colleague receiver1= (Colleague) colleagues.get(receiver);
String text1=text.replaceAll("日","*");
receiver1.receiveText(sender,text1);
}
@Override
public void sendImage(String sender, String receiver, String image) {
Colleague receiver1= (Colleague) colleagues.get(receiver);
if(image.length()>15){
System.out.println("图片太大,发送失败");
}
else{
receiver1.receiveImage(sender,image);
}
}
}
public class Client {
public static void main(String[] args) {
Mediator chatRoom=new ConcreteMediator();
Colleague colleague1,colleague2;
colleague1=new CommonMember("王二");
colleague2=new DiamondMember("王五");
chatRoom.register(colleague1);
chatRoom.register(colleague2);
//测试普通会员的发送权限
System.out.println("普通会员的发送权限: ");
colleague1.sendText("王二","我是普通会员,向你发送文本!");
colleague1.sendImage("王五","我是普通会员,向你发送图片!");
//测试钻石会员发送权限
System.out.println("\n钻石会员发送权限: ");
colleague2.sendText("王二","我是钻石会员,向你发送文本");
colleague2.sendImage("王五","我是钻石会员,向你发送图片!");
//测试过滤不雅字符
System.out.println("\n过滤不雅字符: ");
colleague1.sendText("王五","锄禾日当午");
//测试发送图片大小
System.out.println("\n发送图片大小: ");
colleague2.sendImage("王二","测试图片发送大小aaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
}
【运行截图】
【实验小结】
中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。
中介者模式主要适用于以下情况:
1、系统中对象之间存在比较复杂的引用关系,导致它们之间的依赖关系结构混乱而且难以复用该对象。
2、想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。
用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
实验十三 策略模式的应用
某系统提供了一个用于对数组数据进行操作的类,该类封装了对数组的常见操作,如查找数组元素、对数组元素进行排序等。现以排序操作为例,使用策略模式设计该数组操作类,使得客户端可以动态地更换排序算法,可以根据需要选择冒泡排序或选择排序或插入排序,也能够灵活地增加新的排序算法。
附:三国刘备取西川时,谋士庞统给的上、中、下三个计策:
上策:挑选精兵,昼夜兼行直接偷袭成都,可以一举而定,此为上计计也。
中策:杨怀、高沛是蜀中名将,手下有精锐部队,而且据守关头,我们可以装作要回荆州,引他们轻骑来见,可就此将其擒杀,而后进兵成都,此为中计。
下策:退还白帝,连引荆州,慢慢进图益州,此为下计。
这三个计策都是取西川的计策,也就是攻取西川这个问题的具体的策略算法,刘备可以采用上策,可以采用中策,当然也可以采用下策,由此可见策略模式的各种具体的策略算法都是平等的,可以相互替换。
那谁来选择具体采用哪种计策(算法)?
在这个故事中当然是刘备选择了,也就是外部的客户端选择使用某个具体的算法,然后把该算法(计策)设置到上下文当中;
还有一种情况就是客户端不选择具体的算法,把这个事交给上下文,这相当于刘备说我不管有哪些攻取西川的计策,我只要结果(成功的拿下西川),具体怎么攻占(有哪些计策,怎么选择)由参谋部来决定(上下文)。
用JAVA语言实现 (或C#控制台应用程序实现)该OEM制造商的命令模式。绘制该模式的UML图。
【模式代码(JAVA语言实现)】
Sort.Java
public interface Sort {
public int[] sort(int[] arr);
}
ArrayHandler.java
public class ArrayHandler{
public Sort sortStraregy;
public void setStraregy(Sort sortStraregy) {
this.sortStraregy=sortStraregy;
}
public int[] sort(int[] arr) {
sortStraregy.sort(arr);
return arr;
}
}
Client.java
public class Client {
public static void main(String[] args) {
ArrayHandler ct=new ArrayHandler();
Sort strategy=new BubbleSort();//确定用哪一个排序算法
ct.setStraregy(strategy);
int[] arr= {3,2,5,6,9,7};
int[] result;
result=ct.sort(arr);
for(int i=0;i<result.length;i++) {
System.out.print(result[i]+",");
}
}
}
BubbleSort.java
public class BubbleSort implements Sort {
@Override
public int[] sort(int[] arr) {
int len=arr.length;
for(int i=0;i<len;i++) {
for(int j=i+1;j<len;j++) {
int temp;
if(arr[j]<arr[i]) {
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}
System.out.println("Bubble Sort..........");
return arr;
}
}
InsertionSort.java
public class InsertionSort implements Sort {
@Override
public int[] sort(int[] arr) {
return null;
}
}
SelectSort.java
public class SelectSort implements Sort {
@Override
public int[] sort(int[] arr) {
return null;
}
}
IOccupationStrategyWestOfSiChuan.java
public interface IOccupationStrategyWestOfSiChuan {
public void occupationWestOfSiChuan(String msg);
}
UpperStrategy.java
public class UpperStrategy implements IOccupationStrategyWestOfSiChuan {
@Override
public void occupationWestOfSiChuan(String msg) {
if (msg == null || msg.length() < 5) {
//故意设置障碍,导致上上计策失败
System.out.println("由于计划泄露,上上计策失败!");
int i = 100/0;
}
System.out.println("挑选精兵,昼夜兼行直接偷袭成都,可以一举而定,此为上计计也!");
}
}
MiddleStrategy.java
public class MiddleStrategy implements IOccupationStrategyWestOfSiChuan {
@Override
public void occupationWestOfSiChuan(String msg) {
System.out.println("杨怀、高沛是蜀中名将,手下有精锐部队,而且据守关头,我们可以装作要回荆州,引他们轻骑来见,可就此将其擒杀,而后进兵成都,此为中计。");
}
}
LowerStrategy.java
public class LowerStrategy implements IOccupationStrategyWestOfSiChuan {
@Override
public void occupationWestOfSiChuan(String msg) {
System.out.println("退还白帝,连引荆州,慢慢进图益州,此为下计。");
}
}
OccupationContext.java
public class OccupationContext {
public void occupationWestOfSichuan(String msg){
//先用上上计策
IOccupationStrategyWestOfSiChuan strategy = new UpperStrategy();
try {
strategy.occupationWestOfSiChuan(msg);
} catch (Exception e) {
//上上计策有问题行不通之后,用中计策
strategy = new MiddleStrategy();
strategy.occupationWestOfSiChuan(msg);
}
}
}
Client.java
public class Client {
public static void main(String[] args) {
OccupationContext context = new OccupationContext();
//这个给手下的人激励不够啊
context.occupationWestOfSichuan("拿下西川");
System.out.println("=========================");
//这个人人有赏,让士兵有动力啊
context.occupationWestOfSichuan("拿下西川之后,人人有赏!");
}
}
【实验小结】
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
通过本次实验,学会了使用策略模式。策略模式的适用性如下:
(1)如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
(2)一个系统需要动态地在几种算法中选择一种。
(3)如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
实验十四 状态模式的应用
论坛用户等级
在某论坛系统中,用户可以发表留言,发表留言将增加积分;用户也可以回复留言,回复留言也将增加积分;用户还可以下载文件,下载文件将扣除积分。该系统用户分为三个等级,分别是新手、高手和专家,这三个等级对应三种不同的状态,这三种状态分别定义如下:
(1) 如果积分小于100分,则为新手状态,用户可以发表留言、回复留言,但是不能下载文件。如果积分大于等于1000分,则转换为专家状态;如果积分大于等于100分,则转换为高手状态。
(2) 如果积分大于等于100分但小于1000分,则为高手状态,用户可以发表留言、回复留言,还可以下载文件,而且用户在发表留言时可以获取双倍积分。如果积分小于100分,则转换为新手状态;如果积分大于等于1000分,则转换为专家状态;如果下载文件后积分小于0,则不能下载该文件。
(3) 如果积分大于等于1000分,则为专家状态,用户可以发表留言、回复留言和下载文件,用户除了在发表留言时可以获取双倍积分外,下载文件只扣除所需积分的一半。如果积分小于100分,则转换为新手状态;如果积分小于1000分,但大于等于100,则转换为高手状态;如果下载文件后积分小于0,则不能下载该文件。
用JAVA语言实现(C#控制台应用程序实现)状态模式。绘制该模式的UML图。
【模式UML图】
【模式代码】
public abstract class AbstractState
{
protected ForumAccount acc;
protected int point;
protected String stateName;
public abstract void checkState(int score);
public void downloadFile(int score)
{
System.out.println(acc.getName() + "下载文件,扣除" + score + "积分。");
this.point-=score;
checkState(score);
System.out.println("剩余积分为:" + this.point + ",当前级别为:" + acc.getState().stateName + "。");
}
public void writeNote(int score)
{
System.out.println(acc.getName() + "发布留言" + ",增加" + score + "积分。");
this.point+=score;
checkState(score);
System.out.println("剩余积分为:" + this.point + ",当前级别为:" + acc.getState().stateName + "。");
}
public void replyNote(int score)
{
System.out.println(acc.getName() + "回复留言,增加" + score + "积分。");
this.point+=score;
checkState(score);
System.out.println("剩余积分为:" + this.point + ",当前级别为:" + acc.getState().stateName + "。");
}
public void setPoint(int point) {
this.point = point;
}
public int getPoint() {
return (this.point);
}
public void setStateName(String stateName) {
this.stateName = stateName;
}
public String getStateName() {
return (this.stateName);
}
}
public class ForumAccount
{
private AbstractState state;
private String name;
public ForumAccount(String name)
{
this.name=name;
this.state=new PrimaryState(this);
System.out.println(this.name + "注册成功!");
System.out.println("\n\n");
}
public void setState(AbstractState state)//需要调整状态类的引用
{
this.state=state;
}
public AbstractState getState()
{
return this.state;
}
public void setName(String name)
{
this.name=name;
}
public String getName()
{
return this.name;
}
public void downloadFile(int score)
{
state.downloadFile(score);
}
public void writeNote(int score)
{
state.writeNote(score);
}
public void replyNote(int score)
{
state.replyNote(score);
}
}
public class PrimaryState extends AbstractState
{
public PrimaryState(AbstractState state)
{
this.acc=state.acc;
this.point=state.getPoint();
this.stateName="新手";
}
public PrimaryState(ForumAccount acc)
{
this.point=0;
this.acc=acc;
this.stateName="新手";
}
public void downloadFile(int score)//重写了该方法,因为新手没有下载权限
{
System.out.println("对不起," + acc.getName() + ",您没有下载文件的权限!");
}
public void checkState(int score)//每次执行与积分相关的操作,都要检查自己的积分处于什么状态,让环境类指向这个类型的状态类。
{
if(point>=1000)
{
acc.setState(new HighState(this));
}
else if(point>=100)
{
acc.setState(new MiddleState(this));
}
}
}
public class MiddleState extends AbstractState
{
public MiddleState(AbstractState state)
{
this.acc=state.acc;
this.point=state.getPoint();
this.stateName="高手";
}
public void writeNote(int score)
{
System.out.println(acc.getName() + "发布留言" + ",增加" + score + "*2个积分。");
this.point+=score*2;
checkState(score);
System.out.println("剩余积分为:" + this.point + ",当前级别为:" + acc.getState().stateName + "。");
}
public void checkState(int score)
{
if(point>=1000)
{
acc.setState(new HighState(this));
}
else if(point<0)
{
System.out.println("余额不足,文件下载失败!");
this.point+=score;
}
else if(point<=100)
{
acc.setState(new PrimaryState(this));
}
}
}
public class HighState extends AbstractState
{
public HighState(AbstractState state)
{
this.acc=state.acc;
this.point=state.getPoint();
this.stateName="专家";
}
public void writeNote(int score)
{
System.out.println(acc.getName() + "发布留言" + ",增加" + score + "*2个积分。");
this.point+=score*2;
checkState(score);
System.out.println("剩余积分为:" + this.point + ",当前级别为:" + acc.getState().stateName + "。");
}
public void downloadFile(int score)
{
System.out.println(acc.getName() + "下载文件,扣除" + score + "/2积分。");
this.point-=score/2;
checkState(score);
System.out.println("剩余积分为:" + this.point + ",当前级别为:" + acc.getState().stateName + "。"); }
public void checkState(int score)
{
if(point<0)
{
System.out.println("余额不足,文件下载失败!");
this.point+=score;
}
else if(point<=100)
{
acc.setState(new PrimaryState(this));
}
else if(point<=1000)
{
acc.setState(new MiddleState(this));
}
}
}
public class Client
{
public static void main(String args[])
{
ForumAccount account=new ForumAccount("王二");
account.writeNote(30);
System.out.println("\n");
account.downloadFile(30);
System.out.println("\n");
account.replyNote(120);
System.out.println("\n");
account.writeNote(60);
System.out.println("\n");
account.downloadFile(80);
System.out.println("\n");
account.downloadFile(200);
System.out.println("\n");
account.writeNote(500);
System.out.println("\n");
account.downloadFile(120);
System.out.println("\n");
}
}
【运行截图】
【实验小结】
在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。
在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。
允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
状态模式主要适用于以下情况:
1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
2.一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态。