原型模式

mac2024-04-20  37

概念

用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象(通过复制生成对象)

角色

Client:客户端角色

          负责使用复制实例的方法生成新的实例

Prototype:抽象原型角色

           负责定义用于复制现有实例来生成新实例的方法

ConcreteProtetype:具体原型类

            负责实现复制现有实例并生成新实例的方法

适用场景

对象种类繁多,午饭将他们整合到一个类的情景

难以根据类生成实例的情景

想解耦框架与生成的实例时(拷贝多个对象供使用,保护性拷贝)

ULM图

 Product接口(Prototype)

 product接口是复制功能接口,继承java.lang.Cloneable

public interface Product extends Cloneable{ //use方法是用于“使用”的方法,具体怎么“使用”,则被交给子类去实现。 public abstract void use(String s); //creatClone方法是用于复制实例的方法 public abstract Product creatClone(); }

Manager类(Client)

Manager类使用Product接口来复制实例

public class Manager { //保存实例的“名字”和“实例”之间的对应关系 private HashMap<String, Product> showcase=new HashMap<String, Product>(); //register方法将接收到的一组“名字”和“Product接口”注册到showcase中。 public void register(String name ,Product product){ showcase.put(name, product); } public Product create(String productname){ Product p=showcase.get(productname); return p.creatClone(); } }

MessageBox类(ConcreteProtorype)

装饰方框样式的具体原型,实现了Product接口,实现复制现有实例并生成新实例的方法。

public class MessageBox implements Product { //保存的是装饰方框使用的字符样式 private char decochar; public MessageBox(char decochar) { this.decochar = decochar; } @Override public void use(String s) { int length=s.getBytes().length; for (int i = 0; i < length+4; i++) { System.out.print(decochar); } System.out.println(""); System.out.println(decochar+" "+s+" "+decochar); for (int i = 0; i < length+4; i++) { System.out.print(decochar); } System.out.println(""); } //该方法用于复制自己 @Override public Product creatClone() { Product p=null; try { p=(Product) clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return p; } }

 UnderlinePen类(ConcreteProtorype)

UnderlinePen类的实现几乎和MessageBox类一样,不同的可能只是use方法的实现。

public class UnderlinePen implements Product { private char ulchar; public UnderlinePen(char ulchar) { this.ulchar = ulchar; } @Override public void use(String s) { int length = s.getBytes().length; System.out.println("\""+s+"\""); for (int i = 0; i <length+2; i++) { System.out.print(ulchar); } System.out.println(""); } @Override public Product creatClone() { Product p=null; try { p=(Product) clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return p; } }

Main类

生成Manager实例

public class Main { public static void main(String[] args) { Manager manager = new Manager(); UnderlinePen underlinePen=new UnderlinePen('~'); MessageBox mbox=new MessageBox('*'); MessageBox sbox=new MessageBox('/'); manager.register("Strong message", underlinePen); manager.register("Waring Box", mbox); manager.register("Slash Box", sbox); Product p1=manager.create("Strong message"); p1.use("hello world"); Product p2=manager.create("Waring Box"); p2.use("hello world"); Product p3=manager.create("Slash Box"); p3.use("hello world"); } }

设计与实现

设计思想:名片

1、名片类

package com.xjion.prototype; public class Card implements Cloneable { private String name; private String company; public void setName(String name) { this.name = name; } public void setCompany(String company) { this.company = company; } public Card() { System.out.println("构造函数Card!!!"); } //实现拷贝 @Override protected Card clone() { Card card = null; try { card = (Card) super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return card; } //查看的方法 public void show() { System.out.println("name:"+name); System.out.println("company:"+company); } }

2、使用

package com.xjion.prototype; public class Client { public static void main(String[] args) { Card card = new Card(); card.setName("xjion"); card.setCompany("1688"); Card card2 = card.clone(); card2.setName("xjion1"); card2.setCompany("1688one"); card.show(); card2.show(); } }

注意

实现Cloneable接口,只要重写clone方法就可以实现拷贝,不重写则会报错

clone方法不是Cloneable接口的,而是Object类的方法。

浅拷贝和深拷贝

浅拷贝

如果字段类型是引用类型的情景

1、创建一个公司类

package com.xjion.prototype; public class Company { private String name; private String address; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Company(String name, String address) { super(); this.name = name; this.address = address; } public Company() { super(); // TODO Auto-generated constructor stub } }

 2、名片

package com.xjion.prototype; public class DeepCard implements Cloneable { private String name; private Company company = new Company(); public void setName(String name) { this.name = name; } public void setCompany(String name,String address) { this.company.setName(name); this.company.setAddress(address); } @Override protected DeepCard clone() { DeepCard card = null; try { card = (DeepCard) super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return card; } public void show() { System.out.println("cardName"+name+"---companyName:"+company.getName()+"---addr:"+company.getAddress()); } }

 3、使用

package com.xjion.prototype; public class DeepClient { public static void main(String[] args) { DeepCard card = new DeepCard(); card.setName("小马"); card.setCompany("阿里", "北京"); DeepCard card2 = card.clone(); card2.setName("小马"); card2.setCompany("Tencent", "深圳"); card.show(); card2.show(); } }

注意:

       Object类提供的clone方法,不会拷贝对象内部数组和引用对象,所以导致他们仍然指向原地址,这种拷贝叫做浅拷贝。

       company是引用类型,card被拷贝后,company仍指向原来的card对象的company的地址,所以每次设置都会覆盖前者。

深拷贝

       拷贝Card对象的同时,也把company对象进行拷贝,使得对象永远指向自身的company地址。

1、公司

需要实现Cloneable接口重写clone方法

package com.xjion.prototype2; public class Company implements Cloneable { private String name; private String address; @Override public Company clone() { Company company = null; try { company = (Company) super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return company; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }

2、名片

package com.xjion.prototype2; public class Card implements Cloneable { private String name; private Company company = new Company(); @Override protected Card clone() { Card card = null; try { card = (Card) super.clone(); card.company = this.company.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return card; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Company getCompany() { return company; } public void setCompany(String name,String address) { this.company.setName(name); this.company.setAddress(address); } public void show() { System.out.println("cardName"+name+"---companyName:"+company.getName()+"---addr:"+company.getAddress()); } }

3、使用

package com.xjion.prototype2; public class Client { public static void main(String[] args) { Card card = new Card(); card.setName("大马"); card.setCompany("Tencent","深圳"); Card card2 = card.clone(); card2.setName("小马"); card2.setCompany("1688", "北京"); card.show(); card2.show(); } }

原型模式的特点

是在内存中二进制流的拷贝,比new对象的性能好,特别是需要大量对象时

直接在内存中拷贝,构造函数不会执行,减少了约束

 

 

最新回复(0)