当前位置: 首页 > news >正文

娱乐网站建设流程营销网站开发系统

娱乐网站建设流程,营销网站开发系统,专业做毕业设计网站设计,wordpress 众筹主题1#xff0c;创建型模式 4.1 单例设计模式 单例模式#xff08;Singleton Pattern#xff09;是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式#xff0c;它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类#xff0c;该类负责创建自己…1创建型模式 4.1 单例设计模式 单例模式Singleton Pattern是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类该类负责创建自己的对象同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式可以直接访问不需要实例化该类的对象。 4.1.1 单例模式的结构 单例模式的主要有以下角色 单例类。只能创建一个实例的类访问类。使用单例类 4.1.2 单例模式的实现 单例设计模式分类两种 ​ 饿汉式类加载就会导致该单实例对象被创建 ​ 懒汉式类加载不会导致该单实例对象被创建而是首次使用该对象时才会创建 饿汉式-方式1静态变量方式 /*** 饿汉式* 静态变量创建类的对象*/ public class Singleton {//私有构造方法private Singleton() {}//在成员位置创建该类的对象private static Singleton instance new Singleton();//对外提供静态方法获取该对象public static Singleton getInstance() {return instance;} }说明 ​ 该方式在成员位置声明Singleton类型的静态变量并创建Singleton类的对象instance。instance对象是随着类的加载而创建的。如果该对象足够大的话而一直没有使用就会造成内存的浪费。 饿汉式-方式2静态代码块方式 /*** 恶汉式* 在静态代码块中创建该类对象*/ public class Singleton {//私有构造方法private Singleton() {}//在成员位置创建该类的对象private static Singleton instance;static {instance new Singleton();}//对外提供静态方法获取该对象public static Singleton getInstance() {return instance;} }说明 ​ 该方式在成员位置声明Singleton类型的静态变量而对象的创建是在静态代码块中也是对着类的加载而创建。所以和饿汉式的方式1基本上一样当然该方式也存在内存浪费问题。 懒汉式-方式1线程不安全 /*** 懒汉式* 线程不安全*/ public class Singleton {//私有构造方法private Singleton() {}//在成员位置创建该类的对象private static Singleton instance;//对外提供静态方法获取该对象public static Singleton getInstance() {if(instance null) {instance new Singleton();}return instance;} }说明 ​ 从上面代码我们可以看出该方式在成员位置声明Singleton类型的静态变量并没有进行对象的赋值操作那么什么时候赋值的呢当调用getInstance()方法获取Singleton类的对象的时候才创建Singleton类的对象这样就实现了懒加载的效果。但是如果是多线程环境会出现线程安全问题。 懒汉式-方式2线程安全 /*** 懒汉式* 线程安全*/ public class Singleton {//私有构造方法private Singleton() {}//在成员位置创建该类的对象private static Singleton instance;//对外提供静态方法获取该对象public static synchronized Singleton getInstance() {if(instance null) {instance new Singleton();}return instance;} }说明 ​ 该方式也实现了懒加载效果同时又解决了线程安全问题。但是在getInstance()方法上添加了synchronized关键字导致该方法的执行效果特别低。从上面代码我们可以看出其实就是在初始化instance的时候才会出现线程安全问题一旦初始化完成就不存在了。 懒汉式-方式3双重检查锁 再来讨论一下懒汉模式中加锁的问题对于 getInstance() 方法来说绝大部分的操作都是读操作读操作是线程安全的所以我们没必让每个线程必须持有锁才能调用该方法我们需要调整加锁的时机。由此也产生了一种新的实现模式双重检查锁模式 /*** 双重检查方式*/ public class Singleton { //私有构造方法private Singleton() {}private static Singleton instance;//对外提供静态方法获取该对象public static Singleton getInstance() {//第一次判断如果instance不为null不进入抢锁阶段直接返回实例if(instance null) {synchronized (Singleton.class) {//抢到锁之后再次判断是否为nullif(instance null) {instance new Singleton();}}}return instance;} }双重检查锁模式是一种非常好的单例实现模式解决了单例、性能、线程安全问题上面的双重检测锁模式看上去完美无缺其实是存在问题在多线程的情况下可能会出现空指针问题出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。 要解决双重检查锁模式带来空指针异常的问题只需要使用 volatile 关键字, volatile 关键字可以保证可见性和有序性。 /*** 双重检查方式*/ public class Singleton {//私有构造方法private Singleton() {}private static volatile Singleton instance;//对外提供静态方法获取该对象public static Singleton getInstance() {//第一次判断如果instance不为null不进入抢锁阶段直接返回实际if(instance null) {synchronized (Singleton.class) {//抢到锁之后再次判断是否为空if(instance null) {instance new Singleton();}}}return instance;} }小结 添加 volatile 关键字之后的双重检查锁模式是一种比较好的单例实现模式能够保证在多线程的情况下线程安全也不会有性能问题。 懒汉式-方式4静态内部类方式 静态内部类单例模式中实例由内部类创建由于 JVM 在加载外部类的过程中, 是不会加载静态内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。静态属性由于被 static 修饰保证只被实例化一次并且严格保证实例化顺序。 /*** 静态内部类方式*/ public class Singleton {//私有构造方法private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE new Singleton();}//对外提供静态方法获取该对象public static Singleton getInstance() {return SingletonHolder.INSTANCE;} }说明 ​ 第一次加载Singleton类时不会去初始化INSTANCE只有第一次调用getInstance虚拟机加载SingletonHolder 并初始化INSTANCE这样不仅能确保线程安全也能保证 Singleton 类的唯一性。 小结 ​ 静态内部类单例模式是一种优秀的单例模式是开源项目中比较常用的一种单例模式。在没有加任何锁的情况下保证了多线程下的安全并且没有任何性能影响和空间的浪费。 枚举方式 枚举类实现单例模式是极力推荐的单例实现模式因为枚举类型是线程安全的并且只会装载一次设计者充分的利用了枚举的这个特性来实现单例模式枚举的写法非常简单而且枚举类型是所用单例实现中唯一一种不会被破坏的单例实现模式。 /*** 枚举方式*/ public enum Singleton {INSTANCE; }说明 ​ 枚举方式属于恶汉式方式。 4.1.3 存在的问题 4.1.3.1 问题演示 破坏单例模式 使上面定义的单例类Singleton可以创建多个对象枚举方式除外。有两种方式分别是序列化和反射。 序列化反序列化 Singleton类 public class Singleton implements Serializable {//私有构造方法private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE new Singleton();}//对外提供静态方法获取该对象public static Singleton getInstance() {return SingletonHolder.INSTANCE;} }Test类 public class Test {public static void main(String[] args) throws Exception {//往文件中写对象//writeObject2File();//从文件中读取对象Singleton s1 readObjectFromFile();Singleton s2 readObjectFromFile();//判断两个反序列化后的对象是否是同一个对象System.out.println(s1 s2);}private static Singleton readObjectFromFile() throws Exception {//创建对象输入流对象ObjectInputStream ois new ObjectInputStream(new FileInputStream(C:\\Users\\Think\\Desktop\\a.txt));//第一个读取Singleton对象Singleton instance (Singleton) ois.readObject();return instance;}public static void writeObject2File() throws Exception {//获取Singleton类的对象Singleton instance Singleton.getInstance();//创建对象输出流ObjectOutputStream oos new ObjectOutputStream(new FileOutputStream(C:\\Users\\Think\\Desktop\\a.txt));//将instance对象写出到文件中oos.writeObject(instance);} }上面代码运行结果是false表明序列化和反序列化已经破坏了单例设计模式。 反射 Singleton类 public class Singleton {//私有构造方法private Singleton() {}private static volatile Singleton instance;//对外提供静态方法获取该对象public static Singleton getInstance() {if(instance ! null) {return instance;}synchronized (Singleton.class) {if(instance ! null) {return instance;}instance new Singleton();return instance;}} }Test类 public class Test {public static void main(String[] args) throws Exception {//获取Singleton类的字节码对象Class clazz Singleton.class;//获取Singleton类的私有无参构造方法对象Constructor constructor clazz.getDeclaredConstructor();//取消访问检查constructor.setAccessible(true);//创建Singleton类的对象s1Singleton s1 (Singleton) constructor.newInstance();//创建Singleton类的对象s2Singleton s2 (Singleton) constructor.newInstance();//判断通过反射创建的两个Singleton对象是否是同一个对象System.out.println(s1 s2);} }上面代码运行结果是false表明序列化和反序列化已经破坏了单例设计模式 注意枚举方式不会出现这两个问题。 4.1.3.2 问题的解决 序列化、反序列方式破坏单例模式的解决方法 在Singleton类中添加readResolve()方法在反序列化时被反射调用如果定义了这个方法就返回这个方法的值如果没有定义则返回新new出来的对象。 Singleton类 public class Singleton implements Serializable {//私有构造方法private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE new Singleton();}//对外提供静态方法获取该对象public static Singleton getInstance() {return SingletonHolder.INSTANCE;}/*** 下面是为了解决序列化反序列化破解单例模式*/private Object readResolve() {return SingletonHolder.INSTANCE;} }源码解析 ObjectInputStream类 public final Object readObject() throws IOException, ClassNotFoundException{...// if nested read, passHandle contains handle of enclosing objectint outerHandle passHandle;try {Object obj readObject0(false);//重点查看readObject0方法..... }private Object readObject0(boolean unshared) throws IOException {...try {switch (tc) {...case TC_OBJECT:return checkResolve(readOrdinaryObject(unshared));//重点查看readOrdinaryObject方法...}} finally {depth--;bin.setBlockDataMode(oldMode);} }private Object readOrdinaryObject(boolean unshared) throws IOException {...//isInstantiable 返回true执行 desc.newInstance()通过反射创建新的单例类obj desc.isInstantiable() ? desc.newInstance() : null; ...// 在Singleton类中添加 readResolve 方法后 desc.hasReadResolveMethod() 方法执行结果为trueif (obj ! null handles.lookupException(passHandle) null desc.hasReadResolveMethod()) {// 通过反射调用 Singleton 类中的 readResolve 方法将返回值赋值给rep变量// 这样多次调用ObjectInputStream类中的readObject方法继而就会调用我们定义的readResolve方法所以返回的是同一个对象。Object rep desc.invokeReadResolve(obj);...}return obj; }反射方式破解单例的解决方法 public class Singleton {//私有构造方法private Singleton() {/*反射破解单例模式需要添加的代码*/if(instance ! null) {throw new RuntimeException();}}private static volatile Singleton instance;//对外提供静态方法获取该对象public static Singleton getInstance() {if(instance ! null) {return instance;}synchronized (Singleton.class) {if(instance ! null) {return instance;}instance new Singleton();return instance;}} }说明: ​ 这种方式比较好理解。当通过反射方式调用构造方法进行创建创建时直接抛异常。不运行此中操作。 4.1.4 JDK源码解析-Runtime类 Runtime类就是使用的单例设计模式。 通过源代码查看使用的是哪儿种单例模式 public class Runtime {private static Runtime currentRuntime new Runtime();/*** Returns the runtime object associated with the current Java application.* Most of the methods of class codeRuntime/code are instance* methods and must be invoked with respect to the current runtime object.** return the codeRuntime/code object associated with the current* Java application.*/public static Runtime getRuntime() {return currentRuntime;}/** Dont let anyone else instantiate this class */private Runtime() {}... }从上面源代码中可以看出Runtime类使用的是恶汉式静态属性方式来实现单例模式的。 使用Runtime类中的方法 public class RuntimeDemo {public static void main(String[] args) throws IOException {//获取Runtime类对象Runtime runtime Runtime.getRuntime();//返回 Java 虚拟机中的内存总量。System.out.println(runtime.totalMemory());//返回 Java 虚拟机试图使用的最大内存量。System.out.println(runtime.maxMemory());//创建一个新的进程执行指定的字符串命令返回进程对象Process process runtime.exec(ipconfig);//获取命令执行后的结果通过输入流获取InputStream inputStream process.getInputStream();byte[] arr new byte[1024 * 1024* 100];int b inputStream.read(arr);System.out.println(new String(arr,0,b,gbk));} }4.2 工厂模式 4.2.1 概述 需求设计一个咖啡店点餐系统。 设计一个咖啡类Coffee并定义其两个子类美式咖啡【AmericanCoffee】和拿铁咖啡【LatteCoffee】再设计一个咖啡店类CoffeeStore咖啡店具有点咖啡的功能。 具体类的设计如下 在java中万物皆对象这些对象都需要创建如果创建的时候直接new该对象就会对该对象耦合严重假如我们要更换对象所有new对象的地方都需要修改一遍这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象我们就只和工厂打交道就可以了彻底和对象解耦如果要更换对象直接在工厂里更换该对象即可达到了与对象解耦的目的所以说工厂模式最大的优点就是解耦。 在本教程中会介绍三种工厂的使用 简单工厂模式不属于GOF的23种经典设计模式工厂方法模式抽象工厂模式 4.2.2 简单工厂模式 简单工厂不是一种设计模式反而比较像是一种编程习惯。 4.2.2.1 结构 简单工厂包含如下角色 抽象产品 定义了产品的规范描述了产品的主要特性和功能。具体产品 实现或者继承抽象产品的子类具体工厂 提供了创建产品的方法调用者通过该方法来获取产品。 4.2.2.2 实现 现在使用简单工厂对上面案例进行改进类图如下 工厂类代码如下 public class SimpleCoffeeFactory {public Coffee createCoffee(String type) {Coffee coffee null;if(americano.equals(type)) {coffee new AmericanoCoffee();} else if(latte.equals(type)) {coffee new LatteCoffee();}return coffee;} }工厂factory处理创建对象的细节一旦有了SimpleCoffeeFactoryCoffeeStore类中的orderCoffee()就变成此对象的客户后期如果需要Coffee对象直接从工厂中获取即可。这样也就解除了和Coffee实现类的耦合同时又产生了新的耦合CoffeeStore对象和SimpleCoffeeFactory工厂对象的耦合工厂对象和商品对象的耦合。 后期如果再加新品种的咖啡我们势必要需求修改SimpleCoffeeFactory的代码违反了开闭原则。工厂类的客户端可能有很多比如创建美团外卖等这样只需要修改工厂类的代码省去其他的修改操作。 4.2.2.4 优缺点 优点 封装了创建对象的过程可以通过参数直接获取对象。把对象的创建和业务逻辑层分开这样以后就避免了修改客户代码如果要实现新产品直接修改工厂类而不需要在原代码中修改这样就降低了客户代码修改的可能性更加容易扩展。 缺点 增加新产品时还是需要修改工厂类的代码违背了“开闭原则”。 4.2.2.3 扩展 静态工厂 在开发中也有一部分人将工厂类中的创建对象的功能定义为静态的这个就是静态工厂模式它也不是23种设计模式中的。代码如下 public class SimpleCoffeeFactory {public static Coffee createCoffee(String type) {Coffee coffee null;if(americano.equals(type)) {coffee new AmericanoCoffee();} else if(latte.equals(type)) {coffee new LatteCoffee();}return coffe;} }4.2.3 工厂方法模式 针对上例中的缺点使用工厂方法模式就可以完美的解决完全遵循开闭原则。 4.2.3.1 概念 定义一个用于创建对象的接口让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。 4.2.3.2 结构 工厂方法模式的主要角色 抽象工厂Abstract Factory提供了创建产品的接口调用者通过它访问具体工厂的工厂方法来创建产品。具体工厂ConcreteFactory主要是实现抽象工厂中的抽象方法完成具体产品的创建。抽象产品Product定义了产品的规范描述了产品的主要特性和功能。具体产品ConcreteProduct实现了抽象产品角色所定义的接口由具体工厂来创建它同具体工厂之间一一对应。 4.2.3.3 实现 使用工厂方法模式对上例进行改进类图如下 代码如下 抽象工厂 public interface CoffeeFactory {Coffee createCoffee(); }具体工厂 public class LatteCoffeeFactory implements CoffeeFactory {public Coffee createCoffee() {return new LatteCoffee();} }public class AmericanCoffeeFactory implements CoffeeFactory {public Coffee createCoffee() {return new AmericanCoffee();} }咖啡店类 public class CoffeeStore {private CoffeeFactory factory;public CoffeeStore(CoffeeFactory factory) {this.factory factory;}public Coffee orderCoffee(String type) {Coffee coffee factory.createCoffee();coffee.addMilk();coffee.addsugar();return coffee;} }从以上的编写的代码可以看到要增加产品类时也要相应地增加工厂类不需要修改工厂类的代码了这样就解决了简单工厂模式的缺点。 工厂方法模式是简单工厂模式的进一步抽象。由于使用了多态性工厂方法模式保持了简单工厂模式的优点而且克服了它的缺点。 4.2.3.4 优缺点 优点 用户只需要知道具体工厂的名称就可得到所要的产品无须知道产品的具体创建过程在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类无须对原工厂进行任何修改满足开闭原则 缺点 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类这增加了系统的复杂度。 4.2.4 抽象工厂模式 前面介绍的工厂方法模式中考虑的是一类产品的生产如畜牧场只养动物、电视机厂只生产电视机、传智播客只培养计算机软件专业的学生等。 这些工厂只生产同种类产品同种类产品称为同等级产品也就是说工厂方法模式只考虑生产同等级的产品但是在现实生活中许多工厂是综合型的工厂能生产多等级种类 的产品如电器厂既生产电视机又生产洗衣机或空调大学既有软件专业又有生物专业等。 本节要介绍的抽象工厂模式将考虑多等级产品的生产将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族下图所示横轴是产品等级也就是同一类产品纵轴是产品族也就是同一品牌的产品同一品牌的产品产自同一个工厂。 4.2.4.1 概念 是一种为访问类提供一个创建一组相关或相互依赖对象的接口且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。 抽象工厂模式是工厂方法模式的升级版本工厂方法模式只生产一个等级的产品而抽象工厂模式可生产多个等级的产品。 4.2.4.2 结构 抽象工厂模式的主要角色如下 抽象工厂Abstract Factory提供了创建产品的接口它包含多个创建产品的方法可以创建多个不同等级的产品。具体工厂Concrete Factory主要是实现抽象工厂中的多个抽象方法完成具体产品的创建。抽象产品Product定义了产品的规范描述了产品的主要特性和功能抽象工厂模式有多个抽象产品。具体产品ConcreteProduct实现了抽象产品角色所定义的接口由具体工厂来创建它 同具体工厂之间是多对一的关系。 4.2.4.2 实现 现咖啡店业务发生改变不仅要生产咖啡还要生产甜点如提拉米苏、抹茶慕斯等要是按照工厂方法模式需要定义提拉米苏类、抹茶慕斯类、提拉米苏工厂、抹茶慕斯工厂、甜点工厂类很容易发生类爆炸情况。其中拿铁咖啡、美式咖啡是一个产品等级都是咖啡提拉米苏、抹茶慕斯也是一个产品等级拿铁咖啡和提拉米苏是同一产品族也就是都属于意大利风味美式咖啡和抹茶慕斯是同一产品族也就是都属于美式风味。所以这个案例可以使用抽象工厂模式实现。类图如下 代码如下 抽象工厂 public interface DessertFactory {Coffee createCoffee();Dessert createDessert(); }具体工厂 //美式甜点工厂 public class AmericanDessertFactory implements DessertFactory {public Coffee createCoffee() {return new AmericanCoffee();}public Dessert createDessert() {return new MatchaMousse();} } //意大利风味甜点工厂 public class ItalyDessertFactory implements DessertFactory {public Coffee createCoffee() {return new LatteCoffee();}public Dessert createDessert() {return new Tiramisu();} }如果要加同一个产品族的话只需要再加一个对应的工厂类即可不需要修改其他的类。 4.2.4.3 优缺点 优点 当一个产品族中的多个对象被设计成一起工作时它能保证客户端始终只使用同一个产品族中的对象。 缺点 当产品族中需要增加一个新的产品时所有的工厂类都需要进行修改。 4.2.4.4 使用场景 当需要创建的对象是一系列相互关联或相互依赖的产品族时如电器工厂中的电视机、洗衣机、空调等。 系统中有多个产品族但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。 系统中提供了产品的类库且所有产品的接口相同客户端不依赖产品实例的创建细节和内部结构。 如输入法换皮肤一整套一起换。生成不同操作系统的程序。 4.2.5 模式扩展 简单工厂配置文件解除耦合 可以通过工厂模式配置文件的方式解除工厂对象和产品对象的耦合。在工厂类中加载配置文件中的全类名并创建对象进行存储客户端如果需要对象直接进行获取即可。 第一步定义配置文件 为了演示方便我们使用properties文件作为配置文件名称为bean.properties americancom.itheima.pattern.factory.config_factory.AmericanCoffee lattecom.itheima.pattern.factory.config_factory.LatteCoffee第二步改进工厂类 public class CoffeeFactory {private static MapString,Coffee map new HashMap();static {Properties p new Properties();InputStream is CoffeeFactory.class.getClassLoader().getResourceAsStream(bean.properties);try {p.load(is);//遍历Properties集合对象SetObject keys p.keySet();for (Object key : keys) {//根据键获取值全类名String className p.getProperty((String) key);//获取字节码对象Class clazz Class.forName(className);Coffee obj (Coffee) clazz.newInstance();map.put((String)key,obj);}} catch (Exception e) {e.printStackTrace();}}public static Coffee createCoffee(String name) {return map.get(name);} }静态成员变量用来存储创建的对象键存储的是名称值存储的是对应的对象而读取配置文件以及创建对象写在静态代码块中目的就是只需要执行一次。 4.2.6 JDK源码解析-Collection.iterator方法 public class Demo {public static void main(String[] args) {ListString list new ArrayList();list.add(令狐冲);list.add(风清扬);list.add(任我行);//获取迭代器对象IteratorString it list.iterator();//使用迭代器遍历while(it.hasNext()) {String ele it.next();System.out.println(ele);}} }对上面的代码大家应该很熟使用迭代器遍历集合获取集合中的元素。而单列集合获取迭代器的方法就使用到了工厂方法模式。我们看通过类图看看结构 Collection接口是抽象工厂类ArrayList是具体的工厂类Iterator接口是抽象商品类ArrayList类中的Iter内部类是具体的商品类。在具体的工厂类中iterator()方法创建具体的商品类的对象。 另 ​ 1,DateForamt类中的getInstance()方法使用的是工厂模式 ​ 2,Calendar类中的getInstance()方法使用的是工厂模式 4.3 原型模式 4.3.1 概述 用一个已经创建的实例作为原型通过复制该原型对象来创建一个和原型对象相同的新对象。 4.3.2 结构 原型模式包含如下角色 抽象原型类规定了具体原型对象必须实现的的 clone() 方法。具体原型类实现抽象原型类的 clone() 方法它是可被复制的对象。访问类使用具体原型类中的 clone() 方法来复制新的对象。 接口类图如下 4.3.3 实现 原型模式的克隆分为浅克隆和深克隆。 浅克隆创建一个新对象新对象的属性和原来对象完全相同对于非基本类型属性仍指向原有属性所指向的对象的内存地址。 深克隆创建一个新对象属性中引用的其他对象也会被克隆不再指向原有对象地址。 Java中的Object类中提供了 clone() 方法来实现浅克隆。 Cloneable 接口是上面的类图中的抽象原型类而实现了Cloneable接口的子实现类就是具体的原型类。代码如下 Realizetype具体的原型类 public class Realizetype implements Cloneable {public Realizetype() {System.out.println(具体的原型对象创建完成);}Overrideprotected Realizetype clone() throws CloneNotSupportedException {System.out.println(具体原型复制成功);return (Realizetype) super.clone();} }PrototypeTest测试访问类 public class PrototypeTest {public static void main(String[] args) throws CloneNotSupportedException {Realizetype r1 new Realizetype();Realizetype r2 r1.clone();System.out.println(对象r1和r2是同一个对象 (r1 r2));} }4.3.4 案例 用原型模式生成“三好学生”奖状 同一学校的“三好学生”奖状除了获奖人姓名不同其他都相同可以使用原型模式复制多个“三好学生”奖状出来然后在修改奖状上的名字即可。 类图如下 代码如下 //奖状类 public class Citation implements Cloneable {private String name;public void setName(String name) {this.name name;}public String getName() {return (this.name);}public void show() {System.out.println(name 同学在2020学年第一学期中表现优秀被评为三好学生。特发此状);}Overridepublic Citation clone() throws CloneNotSupportedException {return (Citation) super.clone();} }//测试访问类 public class CitationTest {public static void main(String[] args) throws CloneNotSupportedException {Citation c1 new Citation();c1.setName(张三);//复制奖状Citation c2 c1.clone();//将奖状的名字修改李四c2.setName(李四);c1.show();c2.show();} }4.3.5 使用场景 对象的创建非常复杂可以使用原型模式快捷的创建对象。性能和安全要求比较高。 4.3.6 扩展深克隆 将上面的“三好学生”奖状的案例中Citation类的name属性修改为Student类型的属性。代码如下 //奖状类 public class Citation implements Cloneable {private Student stu;public Student getStu() {return stu;}public void setStu(Student stu) {this.stu stu;}void show() {System.out.println(stu.getName() 同学在2020学年第一学期中表现优秀被评为三好学生。特发此状);}Overridepublic Citation clone() throws CloneNotSupportedException {return (Citation) super.clone();} }//学生类 public class Student {private String name;private String address;public Student(String name, String address) {this.name name;this.address address;}public Student() {}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 class CitationTest {public static void main(String[] args) throws CloneNotSupportedException {Citation c1 new Citation();Student stu new Student(张三, 西安);c1.setStu(stu);//复制奖状Citation c2 c1.clone();//获取c2奖状所属学生对象Student stu1 c2.getStu();stu1.setName(李四);//判断stu对象和stu1对象是否是同一个对象System.out.println(stu和stu1是同一个对象 (stu stu1));c1.show();c2.show();} }运行结果为 说明 ​ stu对象和stu1对象是同一个对象就会产生将stu1对象中name属性值改为“李四”两个Citation奖状对象中显示的都是李四。这就是浅克隆的效果对具体原型类Citation中的引用类型的属性进行引用的复制。这种情况需要使用深克隆而进行深克隆需要使用对象流。代码如下 public class CitationTest1 {public static void main(String[] args) throws Exception {Citation c1 new Citation();Student stu new Student(张三, 西安);c1.setStu(stu);//创建对象输出流对象ObjectOutputStream oos new ObjectOutputStream(new FileOutputStream(C:\\Users\\Think\\Desktop\\b.txt));//将c1对象写出到文件中oos.writeObject(c1);oos.close();//创建对象出入流对象ObjectInputStream ois new ObjectInputStream(new FileInputStream(C:\\Users\\Think\\Desktop\\b.txt));//读取对象Citation c2 (Citation) ois.readObject();//获取c2奖状所属学生对象Student stu1 c2.getStu();stu1.setName(李四);//判断stu对象和stu1对象是否是同一个对象System.out.println(stu和stu1是同一个对象 (stu stu1));c1.show();c2.show();} }运行结果为 注意Citation类和Student类必须实现Serializable接口否则会抛NotSerializableException异常。 4.5 建造者模式 4.4.1 概述 将一个复杂对象的构建与表示分离使得同样的构建过程可以创建不同的表示。 分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于某个对象的构建过程复杂的情况。由于实现了构建和装配的解耦。不同的构建器相同的装配也可以做出不同的对象相同的构建器不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦实现了更好的复用。建造者模式可以将部件和其组装过程分开一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象而无须知道其内部的具体构造细节。 4.4.2 结构 建造者Builder模式包含如下角色 抽象建造者类Builder这个接口规定要实现复杂对象的那些部分的创建并不涉及具体的部件对象的创建。 具体建造者类ConcreteBuilder实现 Builder 接口完成复杂产品的各个部件的具体创建方法。在构造过程完成后提供产品的实例。 产品类Product要创建的复杂对象。 指挥者类Director调用具体建造者来创建复杂对象的各个部分在指导者中不涉及具体产品的信息只负责保证对象各部分完整创建或按某种顺序创建。 类图如下 4.4.3 实例 创建共享单车 生产自行车是一个复杂的过程它包含了车架车座等组件的生产。而车架又有碳纤维铝合金等材质的车座有橡胶真皮等材质。对于自行车的生产就可以使用建造者模式。 这里Bike是产品包含车架车座等组件Builder是抽象建造者MobikeBuilder和OfoBuilder是具体的建造者Director是指挥者。类图如下 具体的代码如下 //自行车类 public class Bike {private String frame;private String seat;public String getFrame() {return frame;}public void setFrame(String frame) {this.frame frame;}public String getSeat() {return seat;}public void setSeat(String seat) {this.seat seat;} }// 抽象 builder 类 public abstract class Builder {protected Bike mBike new Bike();public abstract void buildFrame();public abstract void buildSeat();public abstract Bike createBike(); }//摩拜单车Builder类 public class MobikeBuilder extends Builder {Overridepublic void buildFrame() {mBike.setFrame(铝合金车架);}Overridepublic void buildSeat() {mBike.setSeat(真皮车座);}Overridepublic Bike createBike() {return mBike;} }//ofo单车Builder类 public class OfoBuilder extends Builder {Overridepublic void buildFrame() {mBike.setFrame(碳纤维车架);}Overridepublic void buildSeat() {mBike.setSeat(橡胶车座);}Overridepublic Bike createBike() {return mBike;} }//指挥者类 public class Director {private Builder mBuilder;public Director(Builder builder) {mBuilder builder;}public Bike construct() {mBuilder.buildFrame();mBuilder.buildSeat();return mBuilder.createBike();} }//测试类 public class Client {public static void main(String[] args) {showBike(new OfoBuilder());showBike(new MobikeBuilder());}private static void showBike(Builder builder) {Director director new Director(builder);Bike bike director.construct();System.out.println(bike.getFrame());System.out.println(bike.getSeat());} }注意 上面示例是 Builder模式的常规用法指挥者类 Director 在建造者模式中具有很重要的作用它用于指导具体构建者如何构建产品控制调用先后次序并向调用者返回完整的产品类但是有些情况下需要简化系统结构可以把指挥者类和抽象建造者进行结合 // 抽象 builder 类 public abstract class Builder {protected Bike mBike new Bike();public abstract void buildFrame();public abstract void buildSeat();public abstract Bike createBike();public Bike construct() {this.buildFrame();this.BuildSeat();return this.createBike();} }说明 这样做确实简化了系统结构但同时也加重了抽象建造者类的职责也不是太符合单一职责原则如果construct() 过于复杂建议还是封装到 Director 中。 4.4.4 优缺点 优点 建造者模式的封装性很好。使用建造者模式可以有效的封装变化在使用建造者模式的场景中一般产品类和建造者类是比较稳定的因此将主要的业务逻辑封装在指挥者类中对整体而言可以取得比较好的稳定性。在建造者模式中客户端不必知道产品内部组成的细节将产品本身与产品的创建过程解耦使得相同的创建过程可以创建不同的产品对象。可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中使得创建过程更加清晰也更方便使用程序来控制创建过程。建造者模式很容易进行扩展。如果有新的需求通过实现一个新的建造者类就可以完成基本上不用修改之前已经测试通过的代码因此也就不会对原有功能引入风险。符合开闭原则。 缺点 造者模式所创建的产品一般具有较多的共同点其组成部分相似如果产品之间的差异性很大则不适合使用建造者模式因此其使用范围受到一定的限制。 4.4.5 使用场景 建造者Builder模式创建的是复杂对象其产品的各个部分经常面临着剧烈的变化但将它们组合在一起的算法却相对稳定所以它通常在以下场合使用。 创建的对象较复杂由多个部件构成各部件面临着复杂的变化但构件间的建造顺序是稳定的。创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式即产品的构建过程和最终的表示是独立的。 4.4.6 模式扩展 建造者模式除了上面的用途外在开发中还有一个常用的使用方式就是当一个类构造器需要传入很多参数时如果创建这个类的实例代码可读性会非常差而且很容易引入错误此时就可以利用建造者模式进行重构。 重构前代码如下 public class Phone {private String cpu;private String screen;private String memory;private String mainboard;public Phone(String cpu, String screen, String memory, String mainboard) {this.cpu cpu;this.screen screen;this.memory memory;this.mainboard mainboard;}public String getCpu() {return cpu;}public void setCpu(String cpu) {this.cpu cpu;}public String getScreen() {return screen;}public void setScreen(String screen) {this.screen screen;}public String getMemory() {return memory;}public void setMemory(String memory) {this.memory memory;}public String getMainboard() {return mainboard;}public void setMainboard(String mainboard) {this.mainboard mainboard;}Overridepublic String toString() {return Phone{ cpu cpu \ , screen screen \ , memory memory \ , mainboard mainboard \ };} }public class Client {public static void main(String[] args) {//构建Phone对象Phone phone new Phone(intel,三星屏幕,金士顿,华硕);System.out.println(phone);} }上面在客户端代码中构建Phone对象传递了四个参数如果参数更多呢代码的可读性及使用的成本就是比较高。 重构后代码 public class Phone {private String cpu;private String screen;private String memory;private String mainboard;private Phone(Builder builder) {cpu builder.cpu;screen builder.screen;memory builder.memory;mainboard builder.mainboard;}public static final class Builder {private String cpu;private String screen;private String memory;private String mainboard;public Builder() {}public Builder cpu(String val) {cpu val;return this;}public Builder screen(String val) {screen val;return this;}public Builder memory(String val) {memory val;return this;}public Builder mainboard(String val) {mainboard val;return this;}public Phone build() {return new Phone(this);}}Overridepublic String toString() {return Phone{ cpu cpu \ , screen screen \ , memory memory \ , mainboard mainboard \ };} }public class Client {public static void main(String[] args) {Phone phone new Phone.Builder().cpu(intel).mainboard(华硕).memory(金士顿).screen(三星).build();System.out.println(phone);} }重构后的代码在使用起来更方便某种程度上也可以提高开发效率。从软件设计上对程序员的要求比较高。 4.6 创建者模式对比 4.6.1 工厂方法模式VS建造者模式 工厂方法模式注重的是整体对象的创建方式而建造者模式注重的是部件构建的过程意在通过一步一步地精确构造创建出一个复杂的对象。 我们举个简单例子来说明两者的差异如要制造一个超人如果使用工厂方法模式直接产生出来的就是一个力大无穷、能够飞翔、内裤外穿的超人而如果使用建造者模式则需要组装手、头、脚、躯干等部分然后再把内裤外穿于是一个超人就诞生了。 4.6.2 抽象工厂模式VS建造者模式 抽象工厂模式实现对产品家族的创建一个产品家族是这样的一系列产品具有不同分类维度的产品组合采用抽象工厂模式则是不需要关心构建过程只关心什么产品由什么工厂生产即可。 建造者模式则是要求按照指定的蓝图建造产品它的主要目的是通过组装零配件而产生一个新产品。 如果将抽象工厂模式看成汽车配件生产工厂生产一个产品族的产品那么建造者模式就是一个汽车组装工厂通过对部件的组装可以返回一辆完整的汽车。
http://www.dnsts.com.cn/news/169723.html

相关文章:

  • 不动产登记门户网站建设使用wordpress的建网站
  • 英文网站的外部链接 建设济南网站建设92jzh
  • 类似于wordpress的网站吗5网站建设
  • 浙江建设职业技术学院迎新网站广东网站设计与建设
  • 凡科建站登录入口官方包装设计网站有哪些
  • 优化网站教程淘宝网的公司注册名称
  • 推广网站广告石家庄有那些网站开发公司
  • 挂号网站制作网站建设主机配置
  • html5网站下载seo网站推广是什么
  • 用php写的网站有哪些广州站长
  • 做网站常用的jquery最新军事新闻
  • 做电商的常去网站wordpress 删除 分类存档
  • 外贸网站搭建公司公众号开发运营方案
  • 企业官网怎么和别的网站做链接百度推广注册
  • 网站开发与数据库ppt关键词点击排名系统
  • 网站建设公司长春工程造价建设信息网站
  • 网站开发询价表模板下载汽车4s店网站建设策划
  • 广东省建设项目安全标准自评网站专业建设网站服务公司
  • 样式网站如何创造一个小程序
  • 仿做网站网站切削工具东莞网站建设
  • 做cpa联盟必须要有网站吗江苏工程造价信息网
  • 网站seo好学吗相亲网站怎么建设
  • 网站品牌建设流程网上美工培训
  • 英文网站提交网站目录文件
  • wordpress ownclound太原seo网站排名
  • jsp网站建设项目实战洛阳app开发公司
  • wordpress站内跳转社区电商平台排行榜
  • 郑州网站建设最低价阳江问政平台
  • 婚纱定制网站哪个好wordpress 副标题调用
  • 知名的定制网站建设提供商建设招标网站