设计模式组合模式-外观模式-享元模式
- 组合模式
-
基本介绍
- 组合模式又叫部分整体模式,它创建了对象组的树形结构,将对象组合成树状结构以表示“整体-部分”的层次关系。
- 组合模式依据树形结构来组合对象,用来表示部分以及整体层次。
- 这种类型的设计属于结构型模式。
- 组合模式使得用户对单个对象和组合对象的访问具有一致性,即:组合能让客户一致的方式处理个别对象以及组合对象。
-
组合模式解决的问题
- 当我们的要处理的对象可以生成一颗树形结构,而我们要对树上的节点和叶子进行操作时,它能够提供一致的方式,而不用考虑它是节点还是叶子。
-
代码
public abstract class OrganizationComponent { private String name; private String des; public OrganizationComponent(String name, String des) { super(); this.name = name; this.des = des; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDes() { return des; } public void setDes(String des) { this.des = des; } protected void add(OrganizationComponent organizationComponent) { //默认实现 throw new UnsupportedOperationException(); } protected void remove(OrganizationComponent organizationComponent) { //默认实现 throw new UnsupportedOperationException(); } public abstract void print(); } //University就是Composite可以管理college public class University extends OrganizationComponent { List<OrganizationComponent> organizationComponents=new ArrayList<OrganizationComponent>(); public University(String name, String des) { super(name, des); } @Override protected void add(OrganizationComponent organizationComponent) { organizationComponents.add(organizationComponent); } @Override protected void remove(OrganizationComponent organizationComponent) { organizationComponents.remove(organizationComponent); } @Override public String getName() { return super.getName(); } @Override public String getDes() { return super.getDes(); } @Override public void print() { System.out.println("---------"+getName()+"-------------"); for (OrganizationComponent organizationComponent : organizationComponents) { organizationComponent.print(); } } } public class College extends OrganizationComponent { //存放的是Department List<OrganizationComponent> organizationComponents=new ArrayList<OrganizationComponent>(); public College(String name, String des) { super(name, des); } @Override protected void add(OrganizationComponent organizationComponent) { organizationComponents.add(organizationComponent); } @Override protected void remove(OrganizationComponent organizationComponent) { organizationComponents.remove(organizationComponent); } @Override public String getName() { return super.getName(); } @Override public String getDes() { return super.getDes(); } @Override public void print() { System.out.println("---------"+getName()+"-------------"); for (OrganizationComponent organizationComponent : organizationComponents) { organizationComponent.print(); } } } public class Department extends OrganizationComponent { public Department(String name, String des) { super(name, des); } @Override public String getName() { return super.getName(); } @Override public String getDes() { return super.getDes(); } @Override public void print() { System.out.println("---------"+getName()+"-------------"); } } public class Client { public static void main(String[] args) { OrganizationComponent university=new University("清华大学","中国顶级学校"); OrganizationComponent computerCollege=new College("计算机学院","计算机学院"); OrganizationComponent infoEngineercollege=new College("信息工程学院","信息工程学院"); computerCollege.add(new Department("软件工程","软件编程")); computerCollege.add(new Department("网络工程","网络工程")); computerCollege.add(new Department("计算机科学与技术","计算甲科学与技术")); infoEngineercollege.add(new Department("通信工程","通信工程")); infoEngineercollege.add(new Department("信息工程","信息工程")); university.add(computerCollege); university.add(infoEngineercollege); university.print(); } }
-
组合模式的注意事项和细节
- 简化客户端操作,客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子的问题。
- 具有较强的扩展性,当我们要更改组合对象时,我们只需要调整内部的层次关系,客户端不用做出任何改动。
- 方便创建出复杂的层次结构,客户端不用理会组合里面的细节,容易添加节点或者叶子从而创建出复杂的树形结构。
- 需要遍历组织机构,或者处理的对象具有树形结构2时,非常适合使用组合模式。
- 要求较高的抽象性,如果节点和叶子有很多差异性的话,比如很多方法和属性,都不一样,不适合使用组合模式。
-
- 外观模式
-
基本介绍
- 外观模式,也叫过程模式,外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- 外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统内部的细节。
-
代码
public class DVDPlayer { //使用单例模式 private static DVDPlayer instance=new DVDPlayer(); public static DVDPlayer getInstance() { return instance; } public void on() { System.out.println("dvd on"); } public void off() { System.out.println("dvd off"); } public void play() { System.out.println("dvd is player"); } public void pause() { System.out.println("dvd is pause"); } } public class Popcorn { //使用单例模式 private static Popcorn instance=new Popcorn(); public static Popcorn getInstance() { return instance; } public void on() { System.out.println("popcorn on"); } public void off() { System.out.println("popcorn off"); } public void pop() { System.out.println("popcorn is poping"); } } public class Projector { //使用单例模式 private static Projector instance=new Projector(); public static Projector getInstance() { return instance; } public void on() { System.out.println("projector on"); } public void off() { System.out.println("projector off"); } public void focus() { System.out.println("projector is focus"); } } public class Screen { //使用单例模式 private static Screen instance=new Screen(); public static Screen getInstance() { return instance; } public void on() { System.out.println("screen on"); } public void off() { System.out.println("screen off"); } public void up() { System.out.println("screen up"); } public void down() { System.out.println("screen down"); } } public class Stereo { //使用单例模式 private static Stereo instance=new Stereo(); public static Stereo getInstance() { return instance; } public void on() { System.out.println("Stereo on"); } public void off() { System.out.println("Stereo off"); } public void up() { System.out.println("Stereo up"); } public void down() { System.out.println("Stereo down"); } } public class TheaterLight { //使用单例模式 private static TheaterLight instance=new TheaterLight(); public static TheaterLight getInstance() { return instance; } public void on() { System.out.println("TheaterLight on"); } public void off() { System.out.println("TheaterLight off"); } public void dim() { System.out.println("TheaterLight dim"); } public void bright() { System.out.println("TheaterLight bright"); } } public class HomeTheateFacade { private DVDPlayer dvdPlayer; private Popcorn popcorn; private Projector projector; private Screen screen; private Stereo stereo; private TheaterLight theaterLight; public HomeTheateFacade() { this.dvdPlayer = DVDPlayer.getInstance(); this.popcorn = Popcorn.getInstance(); this.projector = Projector.getInstance(); this.screen = Screen.getInstance(); this.stereo = Stereo.getInstance(); this.theaterLight = TheaterLight.getInstance(); } public void ready() { dvdPlayer.on(); popcorn.on(); popcorn.pop(); projector.on(); stereo.on(); theaterLight.on(); screen.down(); theaterLight.dim(); } public void play() { dvdPlayer.play(); } public void pause() { dvdPlayer.pause(); } public void end() { dvdPlayer.off(); theaterLight.bright(); screen.up(); popcorn.off(); projector.off(); stereo.off(); theaterLight.off(); } } public class Client { public static void main(String[] args) { HomeTheateFacade homeTheateFacade=new HomeTheateFacade(); homeTheateFacade.ready(); homeTheateFacade.play(); homeTheateFacade.end(); } }
-
外观模式的注意事项和细节
- 外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统的使用的复杂性。
- 外观模式对客户端与子系统的耦合关系,让子系统内部的模块更易维护和扩展。
- 通过合理的使用外观模式,可以帮我们更好的划分访问的层次。
- 当系统需要进行分层设计时,可以考虑Facade模式
- 在维护一个遗留的大型系统时,可能这个系统已经变的非常难以维护和扩展,此时可以考虑为新系统开发一个Facade类,来提供提供遗留系统的比较清晰简单的接口,让新系统与Facade类交互,提高复用性。
- 不能过多的或者不合理的使用外观模式,使用外观模式好,还是直接调用模块好。要以让系统有层次,利于维护为目的。
-
- 享元模式
-
基本介绍
- 享元模式也叫蝇量模式:运用共享技术有效地支持大量细粒度的对象。
- 常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个
- 享元模式能够解决重复对象的内存浪费的问题,当系统中有大量相似对象,需要缓冲池时。不需要总是创建新对象,可以从缓冲池里拿。这样可以降低系统内存同时提高效率。
- 享元模式的经典应用场景就是池技术了,string常量池、数据库连接池、缓冲池等等都是享元模式的应用,享元模式是池技术的重要实现方式。
-
内部状态和外部状态
- 享元模式提出了两个要求:细粒度和共享对象。这里涉及到内部状态和外部状态了,即将对象的信息分为两个部分:内部状态和外部状态
- 内部状态指对象共享出来的信息,存储在享元对象内部且不会随环境的改变而改变。
- 外部状态指对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。
-
代码
public abstract class Website { public abstract void use(User user); } //外部状态 public class User { private String name; public User(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } //具体的网站 public class ConcreteWebsite extends Website { //内部状态 private String type=""; //构造方法 public ConcreteWebsite(String type) { this.type = type; } @Override public void use(User user) { System.out.println("网站的发布形式为:"+type+","+user.getName()+"正在使用"); } } public class WebsiteFactory { //集合充当池的作用 private Map<String, ConcreteWebsite> pool=new HashMap<String, ConcreteWebsite>(); //根据网站的类型,返回一个网站,如果没有就创建一个网站并放入到池中 public Website getWebsiteCategory(String type) { ConcreteWebsite wbWebsite; if(!pool.containsKey(type)) { wbWebsite=new ConcreteWebsite(type); pool.put(type, wbWebsite); }else { wbWebsite=pool.get(type); } return wbWebsite; } //获取网站分类的总数(池中有多少个网站类型) public int getWebsiteCount() { return pool.size(); } } public class Client { public static void main(String[] args) { //创建一个工厂类 WebsiteFactory factory=new WebsiteFactory(); //客户端要以新闻的形式发布 Website wbWebsite1=factory.getWebsiteCategory("新闻"); //客户以公总号的形式发布 Website wbWebsite2=factory.getWebsiteCategory("公总号"); Website wbWebsite3=factory.getWebsiteCategory("公总号"); User user1 = new User("小明"); User user2 = new User("小花"); wbWebsite1.use(user1); wbWebsite2.use(user2); wbWebsite3.use(user1); System.out.println(factory.getWebsiteCount()); } }
-
享元模式的注意事项和细节
- 在享元模式这样理解,“享”就表示共享,“元”表示对象。
- 系统中有大量对象,这些对象消耗大量内存,并且对象的状态大部分可以外部化时,我们就可以考虑选用享元模式。
- 用唯一标识码判断,如果在内存中有,则返回这个唯一标识码标识的对象,用HashMap/HashTable存储。
- 享元模式大大减少了对象的创建,降低了程序内存的占用,提高效率。
- 享元模式提高了系统的复杂度。需要分离出内部状态和外部状态,而外部状态具有固话特性,不应该随着内部状态的改变而改变,这是我们使用享元模式需要注意的地方。
- 使用享元模式时,注意划分内部状态和外部状态,并且需要有一个工厂类加以控制。
- 享元模式经典的应用场景是需要缓冲池的场景,比如string常量池、数据库连接池
-