??xml version="1.0" encoding="utf-8" standalone="yes"?> 先看看抽象部分的接口代码: public abstract class Coffee 其中CoffeeImp 是加不加奶的行ؓ接口,看其代码如下: public abstract class CoffeeImp 现在我们有了两个抽象c?span lang=EN-US>,下面我们分别对其q行l承,实现concrete class:
例如,一杯咖啡ؓ?有中杯和大杯之分,同时q有加奶 不加奶之? 如果用单U的l承,q四个具体实?中杯 大杯 加奶 不加?之间有概念重?因ؓ有中杯加?也有中杯不加? 如果再在中杯q一层再实现两个l承,很显然?扩展性极?那我们用Bridge模式来实现它.
如何实现?
以上面提到的咖啡 Z. 我们原来打算只设计一个接?抽象c?,使用Bridge模式?我们需要将抽象和行为分开,加奶和不加奶属于行ؓ,我们它们抽象成一个专门的行ؓ接口.
E序举例Q?br>
{
CoffeeImp coffeeImp;
public void setCoffeeImp() {
this.CoffeeImp = CoffeeImpSingleton.getTheCoffeImp();
}
public CoffeeImp getCoffeeImp() {return this.CoffeeImp;}
public abstract void pourCoffee();
}
{
public abstract void pourCoffeeImp();
}
//中杯 //大杯 |
上面分别是中杯和大杯的具体实?span lang=EN-US>.下面再对行ؓCoffeeImpq行l承:
//加奶 //不加?br>public class FragrantCoffeeImp extends CoffeeImp |
Bridge模式的基本框架我们已l搭好了,别忘记定义中q有一?动态结?我们现在可以喝到臛_四种咖啡:
1.中杯加奶
2.中杯不加?br>3.大杯加奶
4.大杯不加?o:p>
看看是如何动态结合的,在用之?我们做个准备工作,设计一个单态类(Singleton)用来hold当前的CoffeeImp:
public class CoffeeImpSingleton |
看看中杯加奶 和大杯加?是怎么出来?span lang=EN-US>:
//拿出牛奶
CoffeeImpSingleton coffeeImpSingleton = new CoffeeImpSingleton(new MilkCoffeeImp());
//中杯加奶
MediumCoffee mediumCoffee = new MediumCoffee();
mediumCoffee.pourCoffee();
//大杯加奶
SuperSizeCoffee superSizeCoffee = new SuperSizeCoffee();
superSizeCoffee.pourCoffee();
注意: Bridge模式的执行类如CoffeeImp和Coffee是一对一的关p? 正确创徏CoffeeImp是该模式的关?
Z么?span lang=EN-US>Decorator?
我们通常可以使用l承来实现功能的拓展,如果q些需要拓展的功能的种cdJ多,那么势必生成很多子类,增加pȝ的复杂?同时,使用l承实现功能拓展,我们必须可预见这些拓展功?q些功能是编译时q定了,是静态的.
使用Decorator的理由是:q些功能需要由用户动态决定加入的方式和时?Decorator提供?x即用"的方?在运行期间决定何时增加何U功?
E序举例Q?br>Display.java:
public abstract class Display {
public abstract int getColumns(); // 取得横向的字?/p>
public abstract int getRows(); // 取得直向的行?/p>
public abstract String getRowText(int row); // 取得Wrow个字?/p>
public final void show() { // 打印所有內?br> for (int i = 0; i < getRows(); i++) {
System.out.println(getRowText(i));
}
}
}
Border .java:
public abstract class Border extends Display {
protected Display display; // 指装饰外框里面的「內宏V??
protected Border(Display display) { // 在生对象实例时Q以参数指定「內宏V?br> this.display = display;
}
}
public StringDisplay(String string) { // 以参数指定打印的字串
this.string = string;
}
public int getColumns() { // 字数
return string.getBytes().length;
}
public int getRows() { // 行数?
return 1;
}
public String getRowText(int row) { // 仅在row?时才q回
if (row == 0) {
return string;
} else {
return null;
}
}
}
SideBorder.java:
public class SideBorder extends Border {
private char borderChar; // 装饰字符
public SideBorder(Display display, char ch) { // 以构造子指定Display和装饰字W?
super(display);
this.borderChar = ch;
}
public int getColumns() { // 字数要再加上內容两边的装饰字W?br> return 1 + display.getColumns() + 1;
}
public int getRows() { // 行数同內容的行数
return display.getRows();
}
public String getRowText(int row) { // 指定该行的內容即为在內容之指定行的两?br> // 加上装饰字符
return borderChar + display.getRowText(row) + borderChar;
}
}
UpDownBorder .java:
public class UpDownBorder extends Border {
private char borderChar; // 装饰字符
public UpDownBorder(Display display, char ch) { // 以构造子指定Display和装饰字W?br> super(display);
this.borderChar = ch;
}
public int getColumns() { // 字数同內容的字数
return display.getColumns();
}
public int getRows() { // 行数要再加上內容上下的装饰字W的行数
return 1 + display.getRows() + 1;
}
public String getRowText(int row) { // 指定该行的內?br> if (row == 0 || row == getRows() - 1) {
return makeLine(borderChar, getColumns());
} else {
return display.getRowText(row - 1);
}
}
private String makeLine(char ch, int count) { // 以字WchQ徏立重复countơ的q箋字串
StringBuffer buf = new StringBuffer();
for (int i = 0; i < count; i++) {
buf.append(ch);
}
return buf.toString();
}
}
使用Composite
首先定义一个接口或抽象c,q是设计模式通用方式了,其他设计模式Ҏ口内部定义限制不多,Composite却有个规定,那就是要在接口内部定义一个用于访问和理Compositel合体的对象们(或称部gComponentQ?
下面的代码是以抽象类定义Q一般尽量用接口interface,
public abstract class Equipment |
抽象c?span>Equipment是Component定义Q代表着l合体类的对象们,Equipment中定义几个共同的Ҏ?/span>
public class Disk extends Equipment |
Disk是组合体内的一个对象,或称一个部Ӟq个部g是个单独元素( Primitive)?br>q有一U可能是Q一个部件也是一个组合体Q就是说q个部g下面q有'儿子'Q这是树形结构中通常的情况,应该比较Ҏ理解。现在我们先要定义这个组合体Q?/span>
abstract class CompositeEquipment extends Equipment //注意q里Q这里就提供用于讉K自己l合体内的部件方法?br> //上面dIsk 之所以没有,是因为Disk是个单独(Primitive)的元? |
上面CompositeEquipmentl承了Equipment,同时己里面的对象们提供了外部讉K的方?重蝲了Iterator,Iterator是Java的Collection的一个接口,是Iterator模式的实?
我们再看?span>CompositeEquipment的两个具体类:盘盒Chassis和箱子CabinetQ箱子里面可以放很多东西Q如底板Q电源盒Q硬盘盒{;盘盒里面可以放一些小讑֤Q如盘 软驱{。无疑这两个都是属于l合体性质的?/span>
public class Chassis extends CompositeEquipment public class Cabinet extends CompositeEquipment |
x我们完成了整?span>Composite模式的架构?/span>
我们可以看看客户端调?span>Composote代码:
Cabinet cabinet=new Cabinet("Tower");
Chassis chassis=new Chassis("PC Chassis");
//PC Chassis装到Tower?(盘盒装到箱子里)
cabinet.add(chassis);
//一?0GB的硬盘装?PC Chassis (硬盘装到盘盒里)
chassis.add(new Disk("10 GB"));
//调用 netPrice()Ҏ;
System.out.println("netPrice="+cabinet.netPrice());
System.out.println("discountPrice="+cabinet.discountPrice());
上面调用的方?span>netPrice()或discountPrice()Q实际上Composite使用Iterator遍历了整个树形结?L同样包含q个Ҏ的对象ƈ实现调用执行.
Composite是个很y妙体现智慧的模式Q在实际应用中,如果到树Şl构Q我们就可以试是否可以使用q个模式?/span>
设计模式中定?/strong>: 为其他对象提供一U代理以控制对这个对象的讉K.要用再徏?br>E序举例1Q权限访?br>
public class ForumProxy implements Forum { private ForumPermissions permissions; public void setName(String name) throws UnauthorizedException, ... }
private Forum forum;
this.authorization = authorization;
public ForumProxy(Forum forum, Authorization authorization,
ForumPermissions permissions)
{
this.forum = forum;
this.authorization = authorization;
this.permissions = permissions;
}
.....
ForumAlreadyExistsException
{
//只有是系l或论坛理者才可以修改名称
if (permissions.isSystemOrForumAdmin()) {
forum.setName(name);
}
else {
throw new UnauthorizedException();
}
}
?span lang=EN-US>DbForum才是接口Forum的真正实?以修改论坛名UCؓ?
public class DbForum implements Forum, Cacheable { public void setName(String name) throws ForumAlreadyExistsException { ....
} |
凡是涉及到对论坛名称修改q一事g,其他E序都首先得和ForumProxy打交?由ForumProxy军_是否有权限做某一样事?ForumProxy是个名副其实?|关","安全代理pȝ".
E序举例2Q用到才创徏
实际执行打印 Z模仿长时间操?在构建的时候gq?S
public class Printer implements Printable {
private String name;
public Printer() {
heavyJob("正在产生Printer的对象实?);
}
public Printer(String name) { // 构造子
this.name = name;
heavyJob("正在产生Printer的对象实?" + name + ")");
}
public void setPrinterName(String name) { // 命名
this.name = name;
}
public String getPrinterName() { // 取得名称
return name;
}
public void print(String string) { // 输出名称
System.out.println("=== " + name + " ===");
System.out.println(string);
}
private void heavyJob(String msg) { // 较重的工作(假设Q?br> System.out.print(msg);
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.print(".");
}
System.out.println("完成?);
}
}
代理c:真正要打C才去调用生成printerq且参数赋D行打印操?br>public class PrinterProxy implements Printable {
private String name; // 名称
private Printable real; // 「本人?/span>
private String className; // 「本人」的cdU?/span>
public PrinterProxy(String name, String className) { // 构造子
this.name = name;
this.className = className;
}
public synchronized void setPrinterName(String name) { // 命名
if (real != null) {
real.setPrinterName(name); //「本人」也要命?br> }
this.name = name;
}
public String getPrinterName() { // 取得名称
return name;
}
public void print(String string) { // 输出到画面上
realize();
real.print(string);
}
private synchronized void realize() { // 产生「本人?br> if (real == null) {
try {
real = (Printable) Class.forName("Proxy." + className)
.newInstance();
real.setPrinterName(name);
} catch (ClassNotFoundException e) {
System.err.println("找不到类 " + className + "?);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
无论怎么调用setPrinterNameҎ都不会生real实例 只有真正需要生成本人的时候才会生?br>试ҎQ?br>public class Main {
public static void main(String[] args) {
Printable p = new PrinterProxy("Alice", "Printer");
System.out.println("现在的名U是" + p.getPrinterName() + "?);
p.setPrinterName("Bob");
//不会生成Printer
System.out.println("现在的名U是" + p.getPrinterName() + "?);
//不会生成Printer
p.print("Hello, world.");
//生成Printer
}
}
public class Singleton { private Singleton(){} //在自己内部定义自׃个实例,是不是很奇怪? private static Singleton instance = new Singleton(); //q里提供了一个供外部讉K本class的静态方法,可以直接讉K
|
W二UŞ?span>:
public class Singleton { private static Singleton instance = null; }
|
使用Singleton.getInstance()可以讉K单态类?/span>
上面W二中Ş式是lazy initializationQ也是说第一ơ调用时初始SingletonQ以后就不用再生成了?/span>
注意?span>lazy initialization形式中的synchronizedQ这个synchronized很重要,如果没有synchronizedQ那么用getInstance()是有可能得到多个Singleton实例?/span>
一般认为第一UŞ式要更加安全些?/p>
Builder模式是一步一步创Z个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容可以构建它?用户不知道内部的具体构徏l节.Builder模式是非常类似抽象工厂模?l微的区别大概只有在反复使用中才能体会到.
因ؓ一个复杂的对象,不但有很多大量组成部?如汽?有很多部?车轮 方向?发动有各U小零g{等,部g很多,但远不止q些,如何这些部件装配成一辆汽?q个装配q程也很复杂(需要很好的l装技?,Builder模式是Z部件和l装q程分开.
首先,需要一个接?它定义如何创建复杂对象的各个部g:
public interface Builder { //创徏部gA 比如创徏汽R车轮 } |
?span lang=EN-US>Director构徏最后的复杂对象,而在上面Builder接口中封装的是如何创Z个个部g(复杂对象是由q些部gl成?,也就是说Director的内Ҏ如何部件最后组装成成品:
public class Director { private Builder builder; public Director( Builder builder ) { } } |
Builder的具体实现ConcreteBuilder:
通过具体完成接口Builder来构建或装配产品的部?
定义q明它所要创建的是什么具体东?
提供一个可以重新获取品的接口:
public class ConcreteBuilder implements Builder { Part partA, partB, partC; } |
// 实现产生
Product p1 = manager.create("strong message");
p1.use("Hello, world.");
Product p2 = manager.create("warning box");
p2.use("Hello, world.");
Product p3 = manager.create("slash box");
p3.use("Hello, world.");
}
也可以将product声明成抽象类实现Cloneable接口
q且实现createCloneҎ
q样子类中就不用再声明creatCloneҎ?化了代码
cloneҎ在Object中定?因此所有类都会l承clone()Ҏ
Cloneableq个接口表示 可用clone()Ҏq行复制
clone()Ҏ做的是浅拯 所做的操作是直接复制字D内?q不该字段对应的对象实例内?假定有一个数l?当用cloneҎq行拯以后 复制的结果,只是对应到该数组的参?x向该数组的内存地址 如果惛_深拷?必须重写cloneҎ 记得要加上super.clone()
public class Factory{
public static Sample creator(int which){
//getClass 产生Sample 一般可使用动态类装蝲装入cR?br> if (which==1)
return new SampleA();
else if (which==2)
return new SampleB();
}
}
那么在你的程序中,如果要实例化Sample?׃?o:p>
Sample sampleA=Factory.creator(1);
q样,在整个就不涉及到Sample的具体子c?辑ֈ装效果,也就减少错误修改的机?q个原理可以用很通俗的话来比?是具体事情做得多,容易范错误
2、Factory Pattern在父c规定对象的创徏ҎQ但不深入到具体的类名,所有具体的实现都放在了子类Q大致可以分Z生对象实例的大纲(框架)和实际生对象实例的cM斚w
实例Q?br>
framework中的Factory是实现creat的抽象类
public final Product creat(String owner) {
Product p = creadProduct(owner);
registerProduct(p);
return p;
}
public abstract Product creadProduct(String owner);
famework中的Product是仅实现useҎ的抽象类
具体的生成和使用Ҏ都用idcard中的cd体实?br> IDcardFactoryQ?br> IDcardFactory extends Factory
public synchronized Product creadProduct(String owner) {
IDcard ic = new IDcard(owner);
return ic;
}
IDcarrdQ?br>class IDcard extends Product
IDcard(String owner) {
System.out.println("建立" + owner +"的卡");
this.owner = owner;
}
此处构造函C是public 只有通过同一个包中的factory才可以生这个对象实?/p>
public void use() {
System.out.println("使用" + owner + "的卡");
}
具体使用Q?br> public static void main(String[] args) {
Factory fc = new IDcardFactory();
Product p1 = fc.creat("card1");
Product p2 = fc.creat("card2");
Product p3 = fc.creat("card3");
p1.use();
p2.use();
p3.use();
}
q样不必修改framework包中的内容就能够创徏Z同的产品和工?/p>