1、面向对象分析与设计,2,9 设计模式,创建型模式:用于管理对象的创建 Factory Method Abstract Factory Singleton Builder Prototype Simple Factory Object Pool ,3,9 设计模式,行为型模式:用于封装行为的变化 Interpreter Template Method Chain of Responsibility Command Iterator Mediator Memento Observer State Strategy Visitor,4,9 设计模式,结构型模式:用于将以有的代码集成到新的面向对象设计
2、中。 Adapter Bridge Composite Decorator Faade Flyweight Proxy,5,Singleton模式 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 适用性: 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。,6,public class SingletonServer private static SingletonServer ss_instance = null;private SingletonServer() try V
3、ector v = new Vector();v.addElement(“服务器正在运行“);ServerFrameTest.getList().setListData(v); catch (Exception ee) JOptionPane.showMessageDialog(null, “服务器已经在运行!“);System.exit(-1);synchronized public static SingletonServer getInstance() if (ss_instance = null) ss_instance = new SingletonServer();JOptionP
4、ane.showMessageDialog(null, “服务器已经启动!“);return ss_instance; ,7,public class SingletonServer private static class Instance static final SingletonServer ss_instance = new SingletonServer(); private SingletonServer() try Vector v = new Vector(); v.addElement(“服务器正在运行“); ServerFrameTest.getList().setLis
5、tData(v); catch (Exception ee) JOptionPane.showMessageDialog(null, “服务器已经在运行!“); System.exit(-1); public static SingletonServer getInstance() ServerFrameTest.getStartButton().setEnabled(false); return Instance.ss_instance; ,8,这个方案之所以奏效,是因为内部类(Instance)将只被装载一次,所以只会创建一个SingletonServer对象。,9,10,第九章 设计模式
6、,Java简单工厂创建性模式介绍 研究和使用创建性模式的必要性 面向对象的设计的目的之一,就是把责任进行划分,以分派给不同的对象。我们推荐这种划分责任的作法, 是因为它和封装(Encapsulation)和分派(Delegation)的精神是相符合的。创建性模式把对象的创建过程封装起来,使得创建实例的责任与使用实例的责任分割开, 并由专门的模块分管实例的创建,而系统在宏观上不再依赖于对象创建过程的细节。,11,所有面向对象的语言都有固定的创建对象的办法。java的办法就是使用new操作符。比如 StringBuffer s = new StringBuffer(1000); 就创立了一个对象s
7、,其类型是StringBuffer。使用new操作符的短处是事先必须明确知道要实例化的类是什么, 而且实例化的责任往往与使用实例的责任不加区分。使用创建性模式将类实例化,首先不必事先知道每次是要实例化哪一个类, 其次把实例化的责任与使用实例的责任分割开来,可以弥补直接使用new操作符的短处。,12,而工厂模式就是专门负责将大量有共同接口的类实例化,而且不必事先知道每次是要实例化哪一个类的模式。 工厂模式有以下几种形态: 简单工厂(Simple Factory)模式 工厂方法(Factory Method)模式,又称多形性工厂(Polymorphic Factory)模式 抽象工厂(Abstra
8、ct Factory)模式,又称工具箱(Kit或Toolkit)模式,13,简单工厂模式 比如说,你有一个描述你的后花园的系统,在你的后花园里有各种的花,但还没有水果。你现在要往你的系统里引进一些新的类,用来描述下列的水果: 葡萄 Grapes 草莓 Strawberry 萍果 Apple 花和水果最大的不同,就是水果最终是可以采摘食用的。那么,很自然的作法就是建立一个各种水果都适用的接口,这样一来这些水果类作为相似的数据类型就可以和你的系统的其余部分,如各种的花有所不同,易于区分。,14,15,public interface IFruit public abstract void grow
9、();public abstract void harvest();public abstract void plant(); /代码清单1. 接口IFruit的源代码。这个接口确定了水果类必备的方法:种植plant(),生长grow(), 以及收获harvest()。,16,public class Apple implements IFruitprivate int treeAge;public void grow()log(“Apple is growing.“);public void harvest()log(“Apple has been harvested.“);public v
10、oid plant()log(“Apple has been planted.“);public static void log(String msg) System.out.println(msg);public int getTreeAge()return treeAge; public void setTreeAge(int treeAge)this.treeAge = treeAge; /代码清单2. 类Apple的源代码。/萍果是多年生木本植物,因此具备树龄treeAge性质。,17,public class Grape implements IFruitprivate boolea
11、n seedful;public void grow()log(“Grape is growing.“);public void harvest()log(“Grape has been harvested.“);public void plant()log(“Grape has been planted.“);public static void log(String msg)System.out.println(msg);public boolean getSeedful()return seedful;public void setSeedful(boolean seedful)this
12、.seedful = seedful;/代码清单3. 类Grape的源代码。葡萄分为有籽与无籽两种,因此具有 /seedful性质。,18,public class Strawberry implements IFruit public void grow()log(“Strawberry is growing.“);public void harvest()log(“Strawberry has been harvested.“);public void plant()log(“Strawberry has been planted.“);public static void log(Str
13、ing msg)System.out.println(msg); 代码清单4. 类Strawberry的源代码。,19,你作为小花果园的主人兼园丁,也是系统的一部分,自然要由一个合适的类来代表,这个类就是 FruitFactory类。这个类的结构请见下面的UML类图。,20,FruitFactory类会根据要求,创立出不同的水果类,比如萍果Apple,葡萄Grape或草莓Strawberry的实例。而如果接到不合法的要求,FruitFactory类会给出例外BadFruitException。,21,public class FruitFactory public IFruit factory
14、(String which) throws BadFruitException if (which.equalsIgnoreCase(“apple“) return new Apple(); else if (which.equalsIgnoreCase(“strawberry“) return new Strawberry(); else if (which.equalsIgnoreCase(“grape“) return new Grape(); else throw new BadFruitException(“Bad fruit request“); 代码清单5. FruitFacto
15、ry类的源代码。,22,public class BadFruitException extends Exception public BadFruitException(String msg) super(msg); 代码清单6. BadFruitException类的源代码。,23,在使用时,只须呼叫FruitFactory的factory()方法即可 try FruitFactory gardener = new FruitFactory(); gardener.factory(“grape“); gardener.factory(“apple“); gardener.factory(“
16、strawberry“); catch(BadFruitException e) ,24,简单工厂模式的定义 总而言之,简单工厂模式就是由一个工厂类根据参数来决定创立出那一种产品类的实例。下面的UML类图就精确定义了简单工厂模式的结构。,25,public class CreatorFactory public Product factory()return new ConcreteProduct(); public interface Product public abstract ConcreteProduct(); public class ConcreteProduct impleme
17、nts Product public ConcreteProduct() /代码清单7. 简单工厂模式框架的源代码。,26,单工厂模式实际上就是我要在后面介绍的,工厂方法模式的一个简化了的情形。在熟悉了简单工厂模式后,就不难掌握工厂方法模式了。,27,28,29,public class computer public static void main(String args) throws IOException tryBufferedReader br = new BufferedReader(new InputStreamReader(System.in);String strA ;St
18、ring strB ;String strO ;System.out.print(“请输入数据A:“);strA = br.readLine( );System.out.print(“请选择运算符号(+、-、*、/):“);strO= br.readLine();System.out.print(“请输入数据B:“);strB = br.readLine( );String strResult = “;Operation oper = null;oper = OperationFactory.CreateOperate(strO);oper.SetNumberA(Double.valueOf(
19、strA).doubleValue();oper.SetNumberB(Double.valueOf(strB).doubleValue();strResult = Double.toString(oper.GetResult();System.out.print(strResult); catch(Exception e) ,30,Public abstract class Operation private double numberA;private double numberB;public double GetNumberA()return numberA;public void S
20、etNumberA(double a)numberA = a;public double GetNumberB()return numberB;public void SetNumberB(double b)numberB = b;public abstract double GetResult() ,31,public class OperationFactory public static Operation CreateOperate(String oper)Operation operate = null;if(oper.equals(“+“)operate = new Operati
21、onAdd();if(oper.equals(“-“)operate = new OperationSub();return operate; ,32,class OperationAdd extends Operation public double GetResult()double result = 0;result = super.GetNumberA() + super.GetNumberB();return result; ,33,class OperationSub extends Operation public double GetResult()double result=
22、 0;result = super.GetNumberA() - super.GetNumberB();return result; ,34,35,public class computer public static void main(String args) throws IOException tryBufferedReader br = new BufferedReader(new InputStreamReader(System.in);String strA ;String strB ;String strO ;System.out.print(“请输入数据A:“);strA =
23、 br.readLine( );System.out.print(“请选择运算符号(+、-、*、/):“);strO= br.readLine();System.out.print(“请输入数据B:“);strB = br.readLine( );String strResult = “; Operation oper = null;IFactory operFactory = null ;if(strO.equals(“+“)operFactory= new AddFactory();if(strO.equals(“-“)operFactory = new SubFactory();oper
24、 = operFactory.createOperation();,36,oper.SetNumberA(Double.valueOf(strA).doubleValue(); oper.SetNumberB(Double.valueOf(strB).doubleValue();strResult = Double.toString(oper.GetResult();System.out.print(strResult); catch(Exception e) ,37,public abstract class Operation private double numberA;private
25、double numberB;public double GetNumberA()return numberA;public void SetNumberA(double a)numberA = a;public double GetNumberB()return numberB;public void SetNumberB(double b)numberB = b;public abstract double GetResult(); ,38,public interface IFactory public abstract Operation createOperation(); publ
26、ic class AddFactory implements IFactory public Operation createOperation() return new OperationAdd(); ,39,public class SubFactory implements IFactory public Operation createOperation() return new OperationSub(); ,40,class OperationAdd extends Operation public double GetResult()double result = 0;resu
27、lt = super.GetNumberA() + super.GetNumberB();return result; class OperationSub extends Operation public double GetResult()double result= 0;result = super.GetNumberA() - super.GetNumberB();return result; ,41,现在,让我们继续考察我们的小花果园。在一节里,我们在后花园里引进了水果类植物, 构造了简单工厂模式来处理, 使用一个FruitFactory类来负责创立水果类的实例 .,42,43,我们
28、准备再次引进蔬菜类植物,比如 西红柿 (Tomato) 土豆 (Potato) 西芥兰花 (Broccoli) 蔬菜与花和水果当然有共同点,可又有不同之处。蔬菜需要喷洒(dust)杀虫剂(pesticide)除虫, 不同的蔬菜需要喷洒不同的杀虫剂,等等。怎么办呢? 那么,再借用一下简单工厂模式不就行了? 再设计一个专管蔬菜类植物的工厂类,比如,44,45,这样做一个明显的不足点就是不够一般化和抽象化。在FruitFactory和VeggieGardener类之间明显存在很多共同点, 这些共同点应当抽出来一般化和框架化。这样一来,如果后花园的主人决定再在园子里引进些树木类植物时, 我们有框架化的
29、处理方法。本节所要引入的工厂方法模式就符合这样的要求。,46,简单工厂模式涉及到以下的角色 工厂类 (Creator):担任这个角色的是工厂方法模式的核心,是与应用程序紧密相关的,直接在应用程序调用下,创立产品实例的那个类。 工厂类只有一个,而且是实的。 产品 (Product):担任这个角色的类是工厂方法模式所创立的对象的父类,或它们共同拥有的接口。 具体产品 (Concrete Product) :担任这个角色的类是工厂方法模式所创立的具体对象所属的类。,47,工厂方法模式的定义,48,从图可以看出,工厂方法模式涉及到以下的角色 抽象工厂接口(Creator) 担任这个角色的是工厂方法模式
30、的核心,它是与应用程序无关的。任何在模式中创立对象的工厂类必须实现这个接口。 具体工厂类 (Conrete Creator) 担任这个角色的是与应用程序紧密相关的,直接在应用程序调用下,创立产品实例的那样一些类。 产品 (Product) 担任这个角色的类是工厂方法模式所创立的对象的父类,或它们共同拥有的接口。,49,具体产品 (Concrete Product) 担任这个角色的类是工厂方法模式所创立的对象所属的类。 工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式可以允许很多实的工厂类从抽象工厂类继承下来, 从而可以在实际上成为多个简单工厂模式的综
31、合,从而推广了简单工厂模式。,50,反过来讲,简单工厂模式是由工厂方法模式退化而来。设想如果我们非常确定一个系统只需要一个实的工厂类, 那么就不妨把抽象工厂类合并到实的工厂类中去。而这样一来,我们就退化到简单工厂模式了。 与简单工厂模式中的情形一样的是,ConcreteCreator 的factory() 方法返还的数据类型是一个接口 PlantIF,而不是哪一个具体的产品类。这种设计使得工厂类创立哪一个产品类的实例细节完全封装在工厂类内部。,51,好了,现在让我们回到小花果园的系统里,看一看怎样发挥工厂方法模式的威力,解决需要接连不断向小花果园引进不同类别的植物所带来的问题。 首先,我们需要
32、一个抽象工厂类,比如叫做 Gardener,作为两个实工厂类 FruitGardener 及 VeggieGardener 的父类。 Gardener 的 factory() 方法可以是抽象的,留给子类去实现,也可以是实的,在父类实现一部分功能,再在子类实现剩余的功能。我们选择将 factory() 做成抽象的,主要是因为我们的系统是一个示范系统,内容十分简单,没有要在父类实现的任何功能。,52,53,抽象工厂类 Gardener 是工厂方法模式的核心,但是它并不掌握水果类或蔬菜类的生杀大权。相反地,这项权力被交给子类,即 VeggieGardener 及 FruitGardener。 abs
33、tract public class Gardener public abstract PlantIF factory(String which) throws BadFruitException; ,54,public class VeggieGardener extends Gardener public PlantIF factory(String which) throws BadPlantException if (which.equalsIgnoreCase(“tomato“) return new Tomato(); else if (which.equalsIgnoreCase
34、(“potato“) return new Potato(); else if (which.equalsIgnoreCase(“broccoli“) return new Broccoli(); else throw new BadPlantException(“Bad veggie request“); ,55,public class FruitGardener extends Gardener public PlantIF factory(String which) if (which.equalsIgnoreCase(“apple“) return new Apple(); else
35、 if (which.equalsIgnoreCase(“strawberry“) return new Strawberry(); else if (which.equalsIgnoreCase(“grape“) return new Grape(); else throw new BadPlantException(“Bad fruit request“); ,56,public class Apple implements FruitIF, PlantIF public void grow() log(“Apple is growing.“); public void harvest()
36、 log(“Apple has been harvested.“); public void plant() log(“Apple has been planted.“); private static void log(String msg) System.out.println(msg); public int getTreeAge() return treeAge; public void setTreeAge(int treeAge) this.treeAge = treeAge; private int treeAge; ,57,水果类 Apple。与一节里的Apple类相比,唯一的
37、区别就是多实现了一个接口 PlantIF。其它的水果类与 Apple 相似,因此不再赘述。,58,工厂方法模式应该在什么情况下使用 既然工厂方法模式与简单工厂模式的区别很是微妙,那么应该在什么情况下使用工厂方法模式,又应该在什么情况下使用简单工厂模式呢? 一般来说,如果你的系统不能事先确定那一个产品类在哪一个时刻被实例化,从而需要将实例化的细节局域化,并封装起来以分割实例化及使用实例的责任时,你就需要考虑使用某一种形式的工厂模式。,59,在我们的小花果园系统里,我们必须假设水果的种类随时都有可能变化。我们必须能够在引入新的水果品种时,能够很少改动程序,就可以适应变化以后的情况。因此,我们显然需
38、要某一种形式的工厂模式。 如果在发现系统只用一个产品类等级(hierarchy)就可以描述所有已有的产品类,以及可预见的未来可能引进的产品类时,简单工厂模式是很好的解决方案。因为一个单一产品类等级只需要一个单一的实的工厂类。 然而,当发现系统只用一个产品类等级不足以描述所有的产品类,包括以后可能要添加的新的产品类时,就应当考虑采用工厂方法模式。由于工厂方法模式可以容许多个实的工厂类,以每一个工厂类负责每一个产品类等级,因此这种模式可以容纳所有的产品等级,60,在我们的小花果园系统里,不只有水果种类的植物,而且有蔬菜种类的植物。换言之,存在不止一个产品类等级。而且产品类等级的数目也随时都有可能变
39、化。因此,简单工厂模式不能满足需要,为解决向题,我们显然需要工厂方法模式。,61,工资打印程序框架,62,import java.io.BufferedReader; import java.io.InputStreamReader; public class ClientPrint public static void main(String args) tryString stremp;System.out.print(“请输入员工:“);BufferedReader br = new BufferedReader(new InputStreamReader(System.in);stre
40、mp = br.readLine();Employee emp;emp = EmployeeFactory.createEmployee(stremp);emp.getSalary();catch(Exception e) ,63,public class EmployeeFactory public static Employee createEmployee(String emp)Employee employee = null;if(emp.equalsIgnoreCase(“Sales“)employee = new Sales();if(emp.equalsIgnoreCase(“M
41、anagers“)employee = new Managers();if(emp.equalsIgnoreCase(“Engineers“)employee = new Engineers();return employee; ,64,public abstract class Employee public abstract void getSalary(); public class Sales extends Employee Overridepublic void getSalary() / TODO Auto-generated method stubSystem.out.prin
42、t(“Sales:底薪1500元, 提成10%“); ,65,public class Managers extends Employee Overridepublic void getSalary() System.out.print(“Managers:年薪50万元!“); public class Engineers extends Employee Overridepublic void getSalary() System.out.print(“Engineers:月薪5000元“); ,66,Factory Method,Factory Method模式是一个旨在帮助创建责任分配的
43、模式。 意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。 问题:一个类需要实例化另一个类的派生类,但不知道是哪一个。 Factory Method允许派生类进行抉择。 解决方案:派生类对实例化哪个类和如何实例化作出抉择。,67,在java中集合的iterator方法是工厂方法,这一方法返回被请求集合的迭代器的正确类型。 在C#中,集合实现了IEnumerable接口,这一接口定义了GetEnumerator方法,这是获取集合迭代器的工厂方法。,68,69,70,public class ClientPrint public
44、static void main(String args) try String stremp;System.out.print(“请输入员工:“);BufferedReader br = new BufferedReader(new InputStreamReader(System.in);stremp = br.readLine();Employee emp = null;Class cls = (Class) Class.forName(stremp + “Factory“);IEmployeeFactory ief = cls.newInstance();emp = ief.Creat
45、eEmployee();emp.getSalary(); catch (Exception e) ,71,public abstract class Employee public abstract void getSalary(); public interface IEmployeeFactory public abstract Employee CreateEmployee(); ,72,73,public class Engineers extends Employee Overridepublic void getSalary() System.out.print(“Engineer
46、s:月薪5000元“); ,74,public class EngineersFactory implements IEmployeeFactory public Employee CreateEmployee() / TODO Auto-generated method stubreturn new Engineers(); ,75,Factory Method 模式是一个很简单的模式,同学们以后会经常用到它,它可以用于需要将对象实例化的规则推迟到某个派生类的情况,在这种情况下,将方法的实现放在负责该行为的对象中。,76,Abstract Factory,抽象工厂模式是工厂方法模式的进一步扩
47、广化和抽象化.这两个模式区别在于需要创建对象的复杂程度上 意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 适用性 : 一个系统要独立于它的产品的创建、组合和表示时。 一个系统要由多个产品系列中的一个来配置时。 当你要强调一系列相关的产品对象的设计以便进行联合使用时。 当你提供一个产品类库,而只想显示它们的接口而不是实现时。,77,结构,78,79,public class Client private AbstractProductA abstractProductA;private AbstractProductB abstractProductB;public
48、Client(AbstractFactory factory)abstractProductB = (AbstractProductB)factory.CreateProductB();abstractProductA = (AbstractProductA)factory.CreateProductA();public void Run()abstractProductB.Interact(abstractProductA);public static void main(String args)AbstractFactory factory1 = new ConcreteFactory1();Client c1 = new Client(factory1);c1.Run();AbstractFactory factory2 = new ConcreteFactory2();Client c2 = new Client(factory2);c2.Run(); ,