设计模式剖析系列之原型模式

By heiry on 2019-08-06 [ in 技术 ]

用一个已经创建的实例作为原型,克隆(clone)该原型对象来创建一个和原型相同或相似的新对象,免去创建对象的复杂过程和细节。原型模式分浅拷贝与深拷贝两种。

浅拷贝实现方式:

1.原型类实现CLoneable接口

2.拷贝对象通过原型的clone方法获得新的实例

深拷贝实现方式:

1.原型类实现CLoneable接口

2.原型类重写clone方法,并在克隆对象同时也克隆响应的引用类型成员变量。

————————————–

以下通过国宝熊猫的克隆来理解浅拷贝与深拷贝:

熊猫类包含两个成员属性:熊猫名字与饲养员。熊猫名字为普通字符串对象,饲养员为引用对象。以下分别通过浅拷贝和深拷贝两种方式克隆熊猫对象:

浅拷贝方式:

package net.mosang.prototype;
import java.util.Date;
/**
 * 
 * @author heiry
 *
 */
public class Panda implements Cloneable {
  private String name;
  private Feeder feeder;
  
  //重写clone方法
  @Override
  protected Object clone() throws CloneNotSupportedException {
    Panda panda = (Panda) super.clone();
    return panda;
  }

  //setter、getter
  public String getName() {
    return name;
  }


  public void setName(String name) {
    this.name = name;
  }

  public Feeder getFeeder() {
    return feeder;
  }

  public void setFeeder(Feeder feeder) {
    this.feeder = feeder;
  }


  //构造方法

  public Panda(String name, Feeder feeder) {
    super();
    this.name = name;
    this.feeder = feeder;
  }
  
  }
package net.mosang.prototype;

public class Feeder {
  public String name;
  public void feed() {
    System.out.println("feed panda....");
  }
  public Feeder(String name) {
    super();
    this.name = name;
  }
  
}
package net.mosang.prototype;
public class Client {

  public static void main(String[] args) throws CloneNotSupportedException {
    Feeder feeder = new Feed犀利士
er("张大胖");
    Panda p1 = new Panda("pangpang",feeder);
    Panda p2 = (Panda) p1.clone();
    System.out.println(p1);
    System.out.println(p2);
    feeder.name = "张小胖";
    System.out.println("p1----->"+p1+"p1饲养员:----->"+p1.getFeeder().name);
    System.out.println("p2----->"+p2+"p2饲养员:----->"+p2.getFeeder().name);
  }
}

运行结果:

net.mosang.prototype.Panda@15db9742
net.mosang.prototype.Panda@6d06d69c
p1----->net.mosang.prototype.Panda@15db9742p1饲养员:----->张小胖
p2----->net.mosang.prototype.Panda@6d06d69cp2饲养员:----->张小胖

可见浅拷贝方式,虽然获得了一个与原型对象一样的新对象,但是对于引用类型成员变量feeder,拷贝的是地址而不是对象本身,换句话说,两个对象的feeder指向的是同一个Feeder对象。

深拷贝方式:

重点在于重写原型类的clone方法:

package net.mosang.prototype;
/**
 * 
 * @author heiry
 *
 */
public class Panda implements Cloneable{
  private String name;
  private Feeder feeder;
  
  //重写clone方法,并将引用成员变量feeder同时克隆
  @Override
  protected Object clone() throws CloneNotSupportedException {
    Object obj = super.clone();
    Panda panda = (Panda) obj ;
    panda.feeder = (Feeder)this.feeder.clone();
    return panda;
  }

  //setter、getter
  public String getName() {
    return name;
  }


  public void setName(String name) {
    this.name = name;
  }

  public Feeder getFeeder() {
    return feeder;
  }

  public void setFeeder(Feeder feeder) {
    this.feeder = feeder;
  }
  //构造方法
  public Panda(String name, Feeder feeder) {
    super();
    this.name = name;
    this.feeder = feeder;
  }
  }
package net.mosang.prototype;

public class Feeder implements Cloneable{
  public String name;
  public void feed() {
    System.out.println("feed panda....");
  }
  public Feeder(String name) {
    super();
    this.name = name;
  }
  @Override
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
  
}

 

package net.mosang.prototype;
public class Client {

  public static void main(String[] args) throws CloneNotSupportedException {
    Feeder feeder = new Feeder("张大胖");
    Panda p1 = new Panda("pangpang",feeder);
    Panda p2 = (Panda) p1.clone();
    System.out.println(p1);
    System.out.println(p2);
    feeder.name = "张小胖";
    System.out.println("p1----->"+p1+"p1饲养员:----->"+p1.getFeeder().name);
    System.out.println("p2----->"+p2+"p2饲养员:----->"+p2.getFeeder().name);
  }
}

运行结果:

net.mosang.prototype.Panda@15db9742
net.mosang.prototype.Panda@6d06d69c
p1----->net.mosang.prototype.Panda@15db9742p1饲养员:----->张小胖
p2----->net.mosang.prototype.Panda@6d06d69cp2饲养员:----->张大胖

可以看到,深拷贝的引用类型成员变量也是各自独立的。

 

>> 阅读全文  >>

设计模式剖析系列之建造者模式

By heiry on 2019-08-05 [ in 技术 ]

建造者模式

建造者(Builder)模式的主要模块如下:

1. 建造者接口:负责建造各个组件

2.装配者接口:负责将组件组装成产品

3.产品类:成员变量为各组件对象

4.各个组件类

5. 建造者实现类:实现建造者接口

6.装配者实现类:实现装配者接口

7.客户端调用类

这里以建造超级计算机为例,演示构建者模式原理:

假设计算机由CPU/主板/内存三个部件组成,现在要生产一台陌桑超级计算机,CPU为AMD的CPU,主板为华硕主板,内存为256G容量内存。类关系图如下:

使用建造者模式具体做法:

package net.mosang.builder;
/**
 * 具体产品类
 * @author heiry
 *
 */

public class Computer {
  private CPU cpu;
  private Mainboard mainboard;
  private Memory memory;
  
  public CPU getCpu() {
    return cpu;
  }
  public void setCpu(CPU cpu) {
    this.cpu = cpu;
  }
  public Mainboard getMainboard() {
    return mainboard;
  }
  public void setMainboard(Mainboard mainboard) {
    this.mainboard = mainboard;
  }
  public Memory getMemory() {
    return memory;
  }
  public void setMemory(Memory memory) {
    this.memory = memory;
  }
  
}
package net.mosang.builder;
/**
 * 构建子组件接口
 * @author heiry
 *
 */
public interface ComputerBuilder {
  public CPU buildCPU();
  public Mainboard buildMainboard();
  public Memory buildMemory();
}
package net.mosang.builder;
/**
 * 装配者接口
 * @author heiry
 *
 */
public interface ComputerDirector {
  public abstract Computer directComputer();

}
package net.mosang.builder;
/**
 * 构建者实现类
 * 构建陌桑超级计算机部件
 * @author wuah
 *
 */
public class MosangSuperComputer implements ComputerBuilder {

  @Override
  public CPU buildCPU() {
    System.out.println("陌桑超算使用的是AMD的CPU");
    return new CPU("AMD");
  }

  @Override
  public Mainboard buildMainboard() {
    System.out.println("陌桑超算使用的是华硕主板");
    return new Mainboard("华硕");
  }

  @Override
  public Memory buildMemory() {
    System.out.println("陌桑超算使用的是256G内存");
    return new Memory(256);
  }
}
package net.mosang.builder;
/**
 * 装配者实现类:返回具体产品实例
 * 陌桑超算由富士康代工装配
 * @author heiry
 *
 */
public class FoxconnDirector implements ComputerDirector {
  private  ComputerBuilder builder;
  @Override
  public Computer directComputer() {
    CPU cpu = builder.buildCPU();
    Mainboard mainboard = builder.buildMainboard();
    Memory memory = builder.buildMemory();
    Computer c = new Computer();
    c.setCpu(cpu);
    c.setMainboard(mainboard);
    c.setMemory(memory);
    return c;
  }
  
  public FoxconnDirector(ComputerBuilder builder) {
    super();
    this.builder = builder;
  }
}
package net.mosang.builder;
/**
 * 具体部件类:CPU
 * @author heiry
 *
 */
public class CPU {
  private String brands;
  public String getBrands() {
    return brands;
  }

  public void setBrands(String brands) {
    this.brands = brands;
  }

  public CPU(String brands) {
    super();
    this.brands = brands;
  }
  
}
package net.mosang.builder;
/**
 * 具体部件类:内存
 * @author heiry
 *
 */
public class Memory {
  private int capacity;

  public Memory(int capacity) {
    super();
    this.capacity = capacity;
  }

  public int getCapacity() {
    return capacity;
  }

  public void setCapacity(int capacity) {
    this.capacity = capacity;
  }
}
package net.mosang.builder;
/**
 * 具体部件类:主板
 * @author heiry
 *
 */

public class Mainboard {
  private String producer;

  public String getProducer() {
    return producer;
  }

  public void setProducer(String producer) {
    this.producer = producer;
  }

  public Mainboard(String producer) {
    super();
    this.producer = producer;
  }
}
package net.mosang.builder;
/**
 * 客户端调用类
 * @author heiry
 *
 */
public class Client {

  public static void main(String[] args) {
    MosangSuperComputer msc = new MosangSuperComputer();
    FoxconnDirector fd = new FoxconnDirector(msc);
    Computer myComputer = fd.directComputer();
    System.out.println(myComputer);
  }
}

输出结果

陌桑超算使用的是AMD的CPU
陌桑超算使用的是华硕主板
陌桑超算使用的是256G内存
net.mosang.builder.Computer@15db9742

 

>> 阅读全文  >>

设计模式剖析系列之单例模式

By heiry on 2019-08-05 [ in 技术 ]

核心点:

—— 单例类只有一个实例对象;

—— 该单例对象必须由单例类自行创建;

—— 单例类对外提供一个访问该单例的全局访问点;

实现方式:

1.构造方法私有

2.提供类自身定义一个静态私有实例

3.向外提供一个静态的公有方法用于创建或获取该静态私有实例,该方法是对外唯一提供的创建实例途径。

主要分类

——饿汉式:类一旦加载就创建实例,保证在调用静态方法之前单例已经存在了,特点是线程安全。

——懒汉式:只有在第一次调用的时候才会创建,非线程安全,需要考虑线程同步。

 

package net.mosang.singleton;
/**
 * 饿汉式单例模式
 * @author heiry
 *
 */
public class HungrySingLeton {
  private static  HungrySingLeton instance = new HungrySingLeton();
  private HungrySingLeton() {//私有构造方法
  }
  public static HungrySingLeton getInstance() { //对外提供唯一的获取实例方法
    return instance;
  }
}
package net.mosang.singleton;
/**
 * 懒汉式单例模式
 * @author heiry
 *
 */
public class LazySingLeton {
  private static  LazySingLeton instance =null;
  private LazySingLeton() {//私有构造方法
  }
  public static synchronized LazySingLeton getInstance() { //synchronized线程同步,避免并发创建多个对象
    if(instance==null) {
      instance = new LazySingLeton();
    }
    return instance;
  }
}

 

>> 阅读全文  >>

设计模式剖析系列之工厂方法模式

By heiry on 2019-08-05 [ in 技术 ]

工厂方法模式

静态工厂方法只有一个工厂类,且如果要增加产品,则需要修改工厂类代码,违背了开闭原则。工厂方法模式则将工厂类颗粒化,为每一种产品单独设立一个工厂类。

工厂方法模式UML图

package staticfactory;

public interface Computer {
  public abstract void cal();

}
package net.mosang.factory;
public class Mac implements Computer {

  @Override
  public void cal() {
    System.out.println("苹果电脑启动。。。。");
  }
}
package net.mosang.factory;

public class HP implements Computer {

  @Override
  public void cal() {
    System.out.println("惠普电脑启动。。。。");

  }
}
package net.mosang.factory;

public interface ComputerFactoryBasic {
  public abstract Computer CreateComputer();
  
}
package net.mosang.factory;

public class MacFactory implements ComputerFactoryBasic {

  @Override
  public Computer CreateComputer() {
    return new Mac();
  }

}
package net.mosang.factory;

public class HPFactory implements ComputerFactoryBasic {

  @Override
  public Computer CreateComputer() {
    return new HP();
  }

}
package net.mosang.factory;

public class Client {

  public static void main(String[] args) {		
    Computer computer = new MacFactory().CreateComputer();
    Computer computer2 = new HPFactory().CreateComputer();
    computer.cal();
    computer2.cal();
    
  }
}

输出结果

苹果电脑启动。。。。
惠普电脑启动。。。。

 

>> 阅读全文  >>

设计模式剖析系列之静态工厂方法

By heiry on 2019-08-05 [ in 技术 ]

作用:在Think in java 系列书籍以及网上大量的文章都写了其各种各样的好处,我认为言过其实,我们用静态工厂方法,主要原因在于可以根据逻辑需求返回实例对象。可以方便实现工厂模式、单例模式。其它如,有语义方法名、返回其返回类型的任何子类型的对象,方便创建参数化类型实例等等都是无关痛痒的东西。

实现:

将创建实例封装在一个工厂类的静态方法中,静态方法不同的参数返回不同的实例。

示例:

如下所示,电脑工厂类,通过提供静态方法getComputer(String Brand)生产不同品牌的电脑(返回Computer实例对象),客户端只需要调用静态工厂方法传入不同参数即可获得目标对象。

package staticfactory;
public interface Computer {
  public abstract void cal();
}
package staticfactory;
public class Mac implements Computer {
  @Overrid
  public void cal() {
    System.out.println("苹果电脑启动。。。。");
  }
}
package staticfactory;
public class HP implements Computer {
  @Override
  public void cal() {
    System.out.println("惠普电脑启动。。。。");

  }
}
package staticfactory;
public class ComputerFactory {	
  public static Computer getComputer(String computerBrand) {
    switch (computerBrand) {
    case "Mac":
      return new Mac();
    case "HP":
      return new HP();
    default:
      return null;
    }
  }
}
package staticfactory;

public class Client {
  public static void main(String[] args) {
    Computer computer = ComputerFactory.getComputer("Mac");
    Computer computer2 = ComputerFactory.getComputer("HP");
    computer.cal();
    computer2.cal();
  }
}

运行结果:

苹果电脑启动。。。。
惠普电脑启动。。。。

 

>> 阅读全文  >>

设计模式剖析系列之面向对象设计原则

By heiry on 2019-08-04 [ in 技术 ]

一.开闭原则

实现方式:

1. 遵循“抽象约束、封装变化”原则,通过接口或者抽象类为实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中。

2.参数类型、引用对象尽量使用接口或者抽象类,而不是实现类。

3.缩小功能颗粒度。功能粒度越小,被复用的可能性就越大,重复利用可能性就越高。

二. 里氏替换原则

简单地说,把父类都替换成它的子类,程序的行为没有变化。只要出现父类的地方,均可用子类替换,而且对整体实现并没有任何影响,提高代码的复用性。

实现方式:

子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。

三. 依赖倒置原则

——高层模块不应该依赖低层模块,两者都应该依赖其抽象

——抽象不应该依赖细节

——细节应该依赖抽象

实现方式:

1.每个类尽量提供接口或抽象类,或者两者都具备。

2.变量的声明类型尽量是接口或者是抽象,模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的。

3.任何类都不应该从具体类派生。

4.尽量不要重写基类已经写好的方法(符合里氏替换原则)。

>> 阅读全文  >>

设计模式剖析系列之UML类关系

By heiry on 2019-08-04 [ in 技术 ]

设计模式实质上并没有新的东西,只是一种思想体现,来来去去都是在围绕继承、多态、静态之间做文章。很多人学设计模式很吃力,被其中类之间复杂的引用关系绕晕,我认为掌握设计模式最重要的一步就是把常见类之间关系梳理出来,而UML早已经帮我们做了,拿来理顺即可。

一. 依赖关系Dependency

依赖关系是一种临时关系、使用的弱关系,是耦合度最低的一种关系。

代码表现:一个类的方法通过局部变量、方法的参数或者对静态方法的调用来访问另一个类(被依赖类)。下例中,猎人(Hunter)和枪(Gun)之间是一种使用关系,猎人使用枪进行射击,枪Gun作为一个参数出现在猎人shoot方法中(Hunter类中猎杀动作shoot()调用了Gun实例的开火fire()方法):

package com.mosang.umlmodule;

public class Hunter {
  private String name;
  public void shoot(Gun g) {
    g.fire();
  }

}
package com.mosang.umlmodule;

public class Gun {
  private String brand;
  public void fire() {
    System.out.println("shoot.....");
  }
}
package com.mosang.umlmodule;

public class Client {

  public static void main(String[] args) {
    Hunter hunter = new Hunter();
    hunter.shoot(new Gun());

  }
}

UML图示:

二. 关联关系Association

关联关系是对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系,如学生与老师、公司与员工、宠物与主人等等,存在一对一,一对多,多对多等关系。

代码表现:一个类的对象作为另一个类的成员变量。下例中学生与老师是一种多对多的关系(一个学生同时有多个老师教,一个老师也同时教多个学生),Student类作为成员变量出现在Teacher类中,Teacher类也作为成员变量出现在Student类中:

package com.mosang.umlmodule;
import java.util.List;

public class Student {
  private String name;
  private List<Teacher> teachers;
  public void study() {
    
  }
}
package com.mosang.umlmodule;
import java.util.List;

public class Teacher {
  private String name;
  private List<Student> students;
  public void teach() {
    
  }
}

UML图示:

【双向的关联可以用带两个箭头或者没有箭头的实线来表示,单向的关联用带一个箭头的实线来表示,箭头从使用类指向被关联的类。也可以在关联线的两端标注角色名,代表两种不同的角色。】 (更多…)

>> 阅读全文  >>


© 2009-2021 MOSANG.NET DESIGNED BY HEIRY