search
HomeJavajavaTutorialDetailed explanation of composite mechanism in Java

Detailed explanation of composite mechanism in Java

Sep 09, 2017 pm 01:21 PM
javamechanismDetailed explanation

This article mainly introduces relevant information about the detailed examples of composite mechanism in Java. I hope that through this article, everyone can understand the difference between inheritance and composite and apply the composite mechanism. Friends in need can refer to it

Detailed explanation of examples of composite mechanisms in java

The defects of inheritance

The defects of inheritance are caused by its overly powerful functions . Inheritance makes the subclass dependent on the implementation of the superclass. From this point of view, it does not comply with the principle of encapsulation.
Once the superclass changes with a version release, the subclass may be broken, even if its code has not changed at all.

In order to explain more specifically, assuming that we are using HashSet in our program now, we need to add a function to count how many elements have been added to this HashSet since it was created.

Without knowing the flaws of inheritance, we designed a class that inherited HashSet, added an attribute addCount for statistics, and overridden the add and addAll methods. In the method Modify the value of addCount,

The code is as follows:


public class InstrumentedHashSet<E> extends HashSet<E> { 
  // The number of attempted element insertions 
  private int addCount = 0; 
 
  public InstrumentedHashSet() { 
  } 
 
  public InstrumentedHashSet(int initCap, float loadFactor) { 
    super(initCap, loadFactor); 
  } 
 
  @Override public boolean add(E e) { 
    addCount++; 
    return super.add(e); 
  } 
 
  @Override public boolean addAll(Collection<? extends E> c) { 
    addCount += c.size(); 
    return super.addAll(c); 
  } 
 
  public int getAddCount() { 
    return addCount; 
  } 
 
}

This class looks reasonable, but it does not work properly. Execute this paragraph Code:


public static void main(String[] args) { 
  InstrumentedHashSet<String> s = 
    new InstrumentedHashSet<String>(); 
  s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));   
  System.out.println(s.getAddCount()); // expect 3 but 6 
}

Because only three elements were inserted, we expected the getAddCount method to return 3, but in fact it returned 6. What went wrong?

In fact, within HashSet, the addAll method is implemented based on the add method. Therefore, using addAll to add three elements will call addAll once and add three times.
Looking at our overridden method, we will understand why getAddCount returns 6.

Of course, you will say that since HashSet is implemented in this way, then we don’t need to override the addAll method. Yes, that's right.

But although this can work normally, its correctness depends on the fact that the addll method of HashSet is implemented on the add method.

Once the super class modifies the implementation details, our functions may be affected.

In general, inheritance has three natural flaws, which will make the software very fragile:

1) If the subclass calls the method of the parent class, then it will It forms a dependency on the parent class. Once the parent class is changed, the subclass may not work properly.
2) If the parent class adds a new method, and the subclass happens to already provide a method with the same signature but a different return value, then the subclass will not be able to compile.
3) Using inheritance when it should not be done will expose unnecessary APIs to subclasses. In this regard, the Java platform has made mistakes. A typical example is that Properties inherits HashTable, which is unreasonable. The property list is not a hash table, but the Properties in the Java code inherits HashTable. As a result, after the user creates a Properties instance, there is a put There are two methods, setProperties and getProperties. The put and get methods should not be exposed to users.
Because in Properties, both key and value should be String, and HashMap can be other types or even objects.


public class TestProperty { 
  public static void main(String[] args) { 
    Properties properties = new Properties(); 
    properties.setProperty("aaa", "aaa"); 
    properties.put("aaa", new TestPropertyObj()); 
    System.out.println(properties.getProperty("aaa")); // null 
    System.out.println(properties.get("aaa")); // com.hzy.effjava.chp3.item16.TestProperty$TestPropertyObj@5f4fcc96 
  } 
  static class TestPropertyObj { 
     
  } 
}

Composite alternatives to inheritance

The previous section talked about the shortcomings of inheritance, this one Let us take a look at the solution to this problem - compounding.

First we need a class that holds a Set object. This class implements the Set interface. The implementation method calls the corresponding method of the Set object held, so we also call it forwarding. Class:


public class ForwardingSet<E> implements Set<E> { 
  private final Set<E> s; 
  public ForwardingSet(Set<E> s) { this.s = s; } 
 
  public void clear()        { s.clear();      } 
  public boolean contains(Object o) { return s.contains(o); } 
  public boolean isEmpty()     { return s.isEmpty();  } 
  public int size()         { return s.size();   } 
  public Iterator<E> iterator()   { return s.iterator(); } 
  public boolean add(E e)      { return s.add(e);   } 
  public boolean remove(Object o)  { return s.remove(o);  } 
  public boolean containsAll(Collection<?> c) 
                  { return s.containsAll(c); } 
  public boolean addAll(Collection<? extends E> c) 
                  { return s.addAll(c);   } 
  public boolean removeAll(Collection<?> c) 
                  { return s.removeAll(c);  } 
  public boolean retainAll(Collection<?> c) 
                  { return s.retainAll(c);  } 
  public Object[] toArray()     { return s.toArray(); } 
  public <T> T[] toArray(T[] a)   { return s.toArray(a); } 
  @Override public boolean equals(Object o) 
                    { return s.equals(o); } 
  @Override public int hashCode()  { return s.hashCode(); } 
  @Override public String toString() { return s.toString(); } 
}

Then, we can design a class with statistical functions. We only need to inherit the forwarding class we just created, and then the statistical logic code Just write:


public class InstrumentedSet<E> extends ForwardingSet<E> { 
  private int addCount = 0; 
 
  public InstrumentedSet(Set<E> s) { 
    super(s); 
  } 
 
  @Override public boolean add(E e) { 
    addCount++; 
    return super.add(e); 
  } 
  @Override public boolean addAll(Collection<? extends E> c) { 
    addCount += c.size(); 
    return super.addAll(c); 
  } 
  public int getAddCount() { 
    return addCount; 
  } 
 
  public static void main(String[] args) { 
    InstrumentedSet<String> s = 
      new InstrumentedSet<String>(new HashSet<String>()); 
    s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));   
    System.out.println(s.getAddCount()); 
  } 
}

This implementation method avoids all the problems mentioned in the previous section. Since inheritance is not used, it does not depend on the super class. Implementation logic, there is no need to worry about the impact of new methods added to the super class on us.

And there is another advantage of writing this way. This class can add statistical functions to all classes that implement the Set interface, not just HashSet, but also other Sets such as TreeSet.

In fact, this is the decoration mode. InstrumentedSet modifies Set and adds a counting attribute to it.

Summary

Inheritance will destroy the encapsulation of the class, making the subclass very fragile and easily damaged.

Use the composite method to modify the super class to make the subclass more robust and more powerful.

The above is the detailed content of Detailed explanation of composite mechanism in Java. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
How do I use Maven or Gradle for advanced Java project management, build automation, and dependency resolution?How do I use Maven or Gradle for advanced Java project management, build automation, and dependency resolution?Mar 17, 2025 pm 05:46 PM

The article discusses using Maven and Gradle for Java project management, build automation, and dependency resolution, comparing their approaches and optimization strategies.

How do I create and use custom Java libraries (JAR files) with proper versioning and dependency management?How do I create and use custom Java libraries (JAR files) with proper versioning and dependency management?Mar 17, 2025 pm 05:45 PM

The article discusses creating and using custom Java libraries (JAR files) with proper versioning and dependency management, using tools like Maven and Gradle.

How do I implement multi-level caching in Java applications using libraries like Caffeine or Guava Cache?How do I implement multi-level caching in Java applications using libraries like Caffeine or Guava Cache?Mar 17, 2025 pm 05:44 PM

The article discusses implementing multi-level caching in Java using Caffeine and Guava Cache to enhance application performance. It covers setup, integration, and performance benefits, along with configuration and eviction policy management best pra

How can I use JPA (Java Persistence API) for object-relational mapping with advanced features like caching and lazy loading?How can I use JPA (Java Persistence API) for object-relational mapping with advanced features like caching and lazy loading?Mar 17, 2025 pm 05:43 PM

The article discusses using JPA for object-relational mapping with advanced features like caching and lazy loading. It covers setup, entity mapping, and best practices for optimizing performance while highlighting potential pitfalls.[159 characters]

How does Java's classloading mechanism work, including different classloaders and their delegation models?How does Java's classloading mechanism work, including different classloaders and their delegation models?Mar 17, 2025 pm 05:35 PM

Java's classloading involves loading, linking, and initializing classes using a hierarchical system with Bootstrap, Extension, and Application classloaders. The parent delegation model ensures core classes are loaded first, affecting custom class loa

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
1 months agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

SecLists

SecLists

SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool