| Register | FAQ | Calendar | Search | Today's Posts | Mark Forums Read |
|
#61
| |||
| |||
| On 6 May, 17:32, "H. S. Lahman" <h.lah...{}verizon.net> wrote: > Responding to Nicholls... > > > > > > >>>>>>>>>>A::method1(x): > >>>>>>>>>> temp = this.attr1 + x > >>>>>>>>>> temp = Bref.doIt(temp) > >>>>>>>>>> this.attr2 = temp / 5 > > >>>>>>>>>>If we refactor the above to look like this: > > >>>>>>>>>>A::mehod1(x) > >>>>>>>>>>temp = this.attr1 + x > >>>>>>>>>>Bref.doIt(temp) > > >>>>>>>>>>A::method2(x) > >>>>>>>>>>this.attr2 = x / 5 > > >>>>A and B are objects in the same subsystem so they /must/ be at the same > >>>>level of abstraction (i.e., that defined by the subsystem subject matter). > > >>>how do you define subsystem? > > >>Exactly the same way that OMG does in UML. This sort of deflection is > >>something I would expect from Topmind. > > > it is relevant because there are lots of facts you seem to take for > > granted about them. > > > Is it just a set of classes? > > > or does this set have to have some sort of special properties... > > > I would rather deal with sets of classes/types, then I don't have to > > tip toe through your personal definitions. > > I am not going to play this pedantic deflection game. The notion of > 'subsystem' is well-defined in software development in general and for > an OO context in particular (e.g., by OMG per above). There is some > basis for wanting a formal definition of a phrase like 'flexible logical > indivisibility', but asking what a 'subsystem' is just a deflection to > get away from the main point. you imbue it with various properties and behaviour, that I cannot take for granted. > > >>>if type B exists in a another class library...maybe a low level API > >>>into something....is this another subsystem? > > >>Obviously so; it is realized code outside the software being > >>constructed. The library itself provides the API that encapsulates its > >>functionality. > > > that API is some set of 'public' objects......thus 'subsystem' > > collaboration is a special case of 'object collaboration'....thus I > > don't understand any of your conclusions about the status of 'B' and > > how it is 'obviously' anything, why is it 'obviosly' not a private > > implementor?...why is A not 'obviously' a Facade? > > We are talking about OOA/D here. Class libraries are not even visible in > an OOA/D model! (At most they will be identified as a Component in a UML > Component Diagram or in a Deployment Diagram.) so they are visible...... you use the concept subsystems in the defense of your OOA/D design rules, and I am simply trying to clarify by example what these rules mean, if a class library is a subsytem then I can use them as a examples of subsystems, if I then construct a counter example...then something in the rules must be wrong or unclear. > That's because they > represent architectural infrastructure that /supports/ the designed > solution. (Note the one doesn't have class libraries for things like > Customer, Account, and Person unless one is using a DSL.) So they aren't > remotely relevant to this discussion and this is just another deflection > to get away from the main point of the A/B dependency in the first > example above. > They are relevant if you are making specific claims about subsystems and classlibraries are subsystems...then the claims must apply. > > > > > >>OO just provides more convenient mechanisms for the > >>decoupling like the GoF Facade pattern. > > >>>>>This is why I accuse you of flatland design....you don't seem to > >>>>>accept that there are potentially many lower layers of abstraction > >>>>>that *should* be hidden......thus your alleged 'rules' of OO design > >>>>>actually seem to contradict all the established references I know of. > > >>>>My counter is that you do not seem to accept the notion that subsystems > >>>>define the level of abstraction, not objects within subsystems. > > >>>Subsystem....is not a common term in OO circles.... > > >>Say, What?!?!? > > > "This sort of modularization is really basic and it has little to do > > with OO development." > > > I tend to find that OO tends to talk about, classes, objects, sets of > > classes. > > My issue is with the assertion that 'subsystem' is not a common term in > OO circles; that is simply not true. Just a few examples: > > "Object Oriented Analysis" by David Brown. Chapter 12 is entirely > devoted to subsystems. > > "Object Design" by Wirfs-Brock and McKean. Even though her book is > focused object-level design, she provides a definition on pg. 17. (She > also devotes chapter 9 to talking about flexibility, BTW) > > "Object-Oriented Modeling and Design" by Rumbaugh et al. Chapter 9 is > devoted to subsystems. > > "Object-Oriented Software Engineering" by Ivar Jacobson. Multiple > references, mostly in chapter 6, Architecture. > > "Executable UML" by Mellor and Balcer. Chapter 3 is devoted to > subsystems. (In Shlaer-Mellor they are called 'domains'.) > > These were the first 5 books I pulled off my shelf from left to right. > They all talk about subsystems and most talk about them extensively. good...OK.....I'll withdrawer the claim about them not being mentioned much.....you did claim "This sort of modularization is really basic and it has little to do with OO development." which I find odd now in the context of your list of references from books on OO development, but this is a hair split....but I'll withdrawer the claim....I'm just trying to get some clarity around terms. > > >>You may not like the terminology I use, but the basic principles are > >>well-established. So if you think that's not true, find an established > >>OOA/D author who would argue that the first example above is a better > >>way to design the A responsibilities and the collaboration between A and B. > > > I have! > > > GoF...but you wont answer the question. > > I did answer: Facade and the rest of the GoF patterns are not relevant > here because they are at a higher level of abstraction. I don't understand how design patterns are not relevant to your 'rules' of design. > In particular, > almost all of them are about providing a solution to a problem where > dynamic substitution of behavior is too complex to capture in a simple > association. Facade is not about this. > There is no behavior substitution at all in this example, > much less context-dependent substitution. Patterns like Facade are only > relevant to the tangents in this discussion like subsystems. Facade has nothing to do with behaviour substitution...it's about simplyfying a subsystems interface. And thus is directly relevant. > > Ask any one of GoF about the specific examples and they will tell you > the second example above is superior from an OO design perspective. The > example is about dependency at the individual collaboration level. In > the first example the dependency of A's method1 implementation on what > B.doIt does is the core issue. That dependency is a no-no for any OOA/D > author I have ever read, regardless of how much you try to deflect the > discussion. None of this is verifyable. If we refer to GoF......the compiler example (p 191)...it would seem to directly mirror the first construction. Compile is dependent on; Scanner, ProgramNodeBuilder, Parser, Parser::Parse, RISCCodeGenerator, ProgramNode, ProgramNodeBuilder::GetRootNode, ProgramNode::Traverse. is this consistent with your rules or not? > > If you want, take a straw poll of any OO developer still following this > thread and see whether they would prefer the first or second example. > Better yet, post the original example (as the OP did here) in a new > message on comp.object and take a straw poll there. There won't be any > contest because the first example is a classic high level node in a > procedural decomposition while the second represents classic OO > separation of concerns during problem space abstraction. > We can with the above example....well documented. > > > > > >>In contrast, it is you who is consistently mapping procedural paradigms > >>onto OO development with statements like "all dependencies are > >>hierarchical." If the only tool one has is a hammer, the world is full > >>of nails. > > > I am not doing what you do, and you're doing OO, so I must not be? > > >>>>>>When doing problem space abstraction -- long before one starts > >>>>>>to worry about specific collaborations -- one ensures that behavior > >>>>>>responsibilities are self-contained, cohesive, and that their > >>>>>>implementations are encapsulated. > > >>>>>see above....so the examples given are *not* absolute but dependent on > >>>>>the "problem space abstraction".....i.e. if Bref is not part of the > >>>>>problem space but at a lower level of abstraction then it should *not* > >>>>>be designed in the manner shown....and thus we have a 'hierachy' of > >>>>>dependency. > > >>>>Where did I say B did not abstract the subsystem problem space? Where > >>>>did I say it was at a lower level of abstraction? We are talking about > >>>>object collaborations, not subsystem collaborations. Collaborating > >>>>objects should always be at the same level of abstraction. > > >>>High level abstractions must in some sense 'talk' to low level > >>>abstraction else nothing happens. > > >>This really ices my point above. This could be a direct quote from a > >>Structured Programming book. > > > Your doing OO, I'm doing something consistent with Structured > > Programming => I'm not doing OO => I'm wrong? > > You clearly have a lot of development experience. The problem is that it > seems to be primarily procedural. By your own statements you are clearly > mapping procedural paradigms onto OOA/D. Since the construction > paradigms are fundamentally incompatible, that is wrong. (Though neither > paradigm is intrinsically right or wrong when practiced properly.) I do not consider the paradigms to be inconsistent....OO (to me) is a generalisation of procedural coding. > > What you are advocating is analogous to an OO developer working with an > FPL who litters the program with monads to capture state. It's legal and > it will keep the developer in his OO comfort zone, but it is going to > cause anyone steeped in FP to go ballistic. I know of noone 'steeped' in OO to go balistic about the Facade pattern. > > Recall that subsystems only came into this discussion at all because you > kept wanting to talk about the broader context of what the client > expected and about talking to "lower level" services. That is a > quintessential procedural decomposition view. but you yourself have given a list of references about subsystems. I can now use these references.... Chapter 9 Rumbaugh figure 9.1. looks very much like my description... Wirfs-Brock goes on at length about the layered architectural style p32....and figure 1-14 would seem to be a UML version of 'example 1' "delegated control creates pools of application logic". figure 1-15/16 shows a glorious set of dependencies between layers. (though I accept that the logical dependencies may not follow these arrows directly, they would still form a 'tree') > All I did was point out > that subsystems define the level of abstraction for object > collaborations > so that view of decomposition (high level client > expectation vs. low level service) is not at all relevant to the example > dependency because A and B are at the same level of abstraction (i.e., > peers). where do you specify that A & B are at the same level of abstraction....this is what I have argued all along.....if they aren't then example #1 is perfectly valid. > > Also recall that it was you who originally argued in the opening to this > subthread that I was advocating something other that OO development > with, "you are the only one I know of that claims 'peer-to-peer > collaboration is .. fundamental to OO development'....it appears > to be a recipe for a nightmare of flatland complexity.." > > yes......are we quibling about the nature of the word 'peer'...... I know it sounds pedantic, but please define peer in this context..... are there any non 'peer to peer' colloborations? > > > > >>>If we want to compare your examples they will both have to be > >>>executable examples that exhibit the same behaviour. > > >>Actually, that is just another argument for the second example. The > >>methods of A in the second example can be exhaustively unit tested in > >>complete isolation from everything else in the application. That is not > >>true for the first example, where one must have a correct implementation > >>of B.doIt available to test method1. (Stubbing it to return a valid > >>value for a given test case is just self-delusion; all one is testing is > >>the test harness.) > > > If we want to compare your examples they will both have to be > > executable examples that exhibit the same behaviour, then we can judge > > the relative pro's and cons....as they are they are two relatively > > unrelated bits of code. > > That's pretty much the point of unit testing. The examples /are/ > executable for test purposes and it is that execution ... They do not obey the same signatures....thus we cannot run a test against #1, and then run an identical test against test #2.....the point is that for us to scientifically test them, the tests must be the same and only the thing under scrutiny change, we can't rig the test on the basis of what we're testing. > > read more »- Hide quoted text - > > - Show quoted text -- Hide quoted text - > > - Show quoted text -- Hide quoted text - > > - Show quoted text -- Hide quoted text - > > - Show quoted text - |
|
#62
| |||
| |||
| "Mark Nicholls" wrote: > "Leslie Sanford" wrote: <snip> >> I've looked into using a pipes and filter architecture. I usually get >> confused in the details. It's easy enough to understand how to >> implement it when you have a pipeline that doesn't split: <snip> >> So it seems that a push architecture can handle the pipeline forking >> into several pipes but has a harder time handling several pipes >> streaming into one. The pull architecture has just the opposite >> problem. > > yep.... > > I'm not too sure of the application.....if it's some sort of batch > process, I would set the roots to be specific input values....and then > pull the results out of the top (leaves) for a fixed set of > inputs....if you want you can cache results in intermediate filters, > as the values shouldn't change. > >> >> The way I'm currently handling this is to not use a push or pull >> architecture at all. Each filter has an ordering number. It's 1 plus >> the number of other filters connected to it. The filters are sorted >> by this ordering number in ascending order. Each time the pipeline >> needs to filter data, the engine iterates through the sorted >> collection of filters invoking a process method on each filter. Thus >> filters with no connections (data sources) are invoked first while >> filters with the most connections are invoked last. > > oooo....sounds complicated. > > I think you've gone a step further and seperated the processesing, > from the representation.....which is absolutely fine.....your using > pipes and filters to represent the processing and something else > (visitor?) to process the data. Not really Visitor, I think. Maybe I can clarify my approach with some code. In my toolkit I have a Synthesizer class. It represents a musical synthesizer. The Synthesizer uses several voices. Each voice represents functionality for playing a sound. The number of sounds a synthesizer can play at once is called its polyphony. Hence the number of voices it has defines it polyphony. I have an abstract class called Voice representing a voice within a synthesizer. Normally, I shy away from implementation inheritance, but I've found it useful here. The Voice class is meant to be the base class for custom voice classes users can define themselves. Typically, each voice has its own collection of synth type components such as oscillators, filters, envelopes, etc... When a voice is played, i.e. when the synthesizer receives a note-on command and assigns a voice to play the note, it uses its internal components to synthesize the sound. The Synthesizer mixes the outputs of all playing voices into a single buffer that is fed to a waveform output device. The device plays the waveform data resulting in you hearing it at your computer's speakers. Those components I mentioned are all represented by their respective classes. So we have an Oscillator class, a Filter class, and so on. Each of those classes implement a common interface. They provide an "Ordinal" number that I've described before. The more inputs a component has, the higher its ordinal number, i.e. the further down it is in the chain of components. So if we're implementing our own Voice derived class, in the constructor, we could do something like this: public MyVoice() { osc1 = new Oscillator(); osc2 = new Oscillator(); filter = new StateVariableFilter(); amEnvelope = new AdsrEnvelope(); fmEnvelope = new AdsrEnvelope(); // Connect them together: filter.Input1 = osc1; filter.Input2 = osc2; filter.FmModulator = fmEnvelope; filter.AmModulator = amEnvelope; // Call the Add method in the Voice base class to add all of the // components to the Voice's component collection. Add(osc1); Add(osc2); Add(filter); Add(amEnvelope); Add(fmEnveope); } Just a basic synthesizer set up: Two oscillators feeding into one filter. An envelope modulating the filter's cutoff frequency and another envelope modulating its amplitude. fmEnvelope osc1--+ | | v +-->filter--> | ^ osc2--+ | amEnvelope Each of the synth components are added to the base class's collection of components. They're sorted in ascending order according to their ordinal number (I've left some details out here such as the functionality for changing the setup dynamically). When it's time for a Voice to synthesize some waveform data, the Synthesizer calls "Synthesize" on each of the currently playing voices. In turn, each playing voice calls Synthesize on each of its components: public void Synthesize(int startIndex, int count) { foreach(ISynthComponent component in components) { component.Synthesize(startIndex, count); } } That's all there is to it. The order in which Synthesize is called on each component ensures that the component's buffer is ready to be used by any connected components. So in our Filter, we could have something like this: public void Synthesize(int startIndex, int count) { double in1, in2; double output; for(int i = startIndex; i < startIndex + count; i++) { // Access the buffers in the input components. in1 = input1[i]; // Each component allows index access to its // buffer. in2 = input2[i]; // Do filtering stuff... buffer[i] = output; } } And the inputs would be up to date, everything's in sync. Anyway, that was a bit longer than I planned on writing. But it gives you a good idea of the architecture I've been designing. >> The effect of this approach is that the data processed by one filter >> is ready to be processed by the next filter; it takes care of the >> synchronizing problem. Reading data from a filter is a passive >> operation so several filters can read from the same filter without >> changing its state. This seems to take care of the problems described >> above. It also means that the engine that drives all of this can be >> reused no matter what type of filters are in the pipeline. >> >> It requires, though, that someone know which filter is the ultimate >> endpoint. It should be the filter with the most connections. One >> invariant I've thought of implementing is to make sure that there is >> always one and only one filter that has more connections than any of >> the others. The engine could recognize this filter as the last one in >> the chain of filters. > > personally I don't like it....your processing process now seems to be > leaking into your representation of the process. > >> >> I'd appreciate any thoughts anyone would have on this approach. >> Thanks. > > Can you not just pull the data out of the leaves? Yeah, that's one possibility. This is realtime processing, though, and I need to make things as efficient as possible. Mixing the output of several leaves/components together will take time, so I was thinking that a reasonable limit to enforce would be to make sure there's always a root component representing the end of the chain of components. Then the Voice can just read its data. This endpoint component would just be the last component in the collection of sorted components. So it would be easy enough to access provided that the this limit is enforced. |
|
#63
| |||
| |||
| ooo long post. On 8 May, 20:06, "Leslie Sanford" <jabberdab...{}hotmail.com> wrote: > "Mark Nicholls" wrote: > > "Leslie Sanford" wrote: > > <snip> > > >> I've looked into using a pipes and filter architecture. I usually get > >> confused in the details. It's easy enough to understand how to > >> implement it when you have a pipeline that doesn't split: > > <snip> > > > > > > >> So it seems that a push architecture can handle the pipeline forking > >> into several pipes but has a harder time handling several pipes > >> streaming into one. The pull architecture has just the opposite > >> problem. > > > yep.... > > > I'm not too sure of the application.....if it's some sort of batch > > process, I would set the roots to be specific input values....and then > > pull the results out of the top (leaves) for a fixed set of > > inputs....if you want you can cache results in intermediate filters, > > as the values shouldn't change. > > >> The way I'm currently handling this is to not use a push or pull > >> architecture at all. Each filter has an ordering number. It's 1 plus > >> the number of other filters connected to it. The filters are sorted > >> by this ordering number in ascending order. Each time the pipeline > >> needs to filter data, the engine iterates through the sorted > >> collection of filters invoking a process method on each filter. Thus > >> filters with no connections (data sources) are invoked first while > >> filters with the most connections are invoked last. > > > oooo....sounds complicated. > > > I think you've gone a step further and seperated the processesing, > > from the representation.....which is absolutely fine.....your using > > pipes and filters to represent the processing and something else > > (visitor?) to process the data. > > Not really Visitor, I think. Maybe I can clarify my approach with some > code. In my toolkit I have a Synthesizer class. It represents a musical > synthesizer. The Synthesizer uses several voices. Each voice represents > functionality for playing a sound. The number of sounds a synthesizer > can play at once is called its polyphony. Hence the number of voices it > has defines it polyphony. > > I have an abstract class called Voice representing a voice within a > synthesizer. Normally, I shy away from implementation inheritance, but > I've found it useful here. The Voice class is meant to be the base class > for custom voice classes users can define themselves. > > Typically, each voice has its own collection of synth type components > such as oscillators, filters, envelopes, etc... When a voice is played, > i.e. when the synthesizer receives a note-on command and assigns a voice > to play the note, it uses its internal components to synthesize the > sound. The Synthesizer mixes the outputs of all playing voices into a > single buffer that is fed to a waveform output device. The device plays > the waveform data resulting in you hearing it at your computer's > speakers. > > Those components I mentioned are all represented by their respective > classes. So we have an Oscillator class, a Filter class, and so on. Each > of those classes implement a common interface. They provide an "Ordinal" > number that I've described before. The more inputs a component has, the > higher its ordinal number, i.e. the further down it is in the chain of > components. > > So if we're implementing our own Voice derived class, in the > constructor, we could do something like this: > > public MyVoice() > { > osc1 = new Oscillator(); > osc2 = new Oscillator(); > filter = new StateVariableFilter(); > amEnvelope = new AdsrEnvelope(); > fmEnvelope = new AdsrEnvelope(); > > // Connect them together: > filter.Input1 = osc1; > filter.Input2 = osc2; > filter.FmModulator = fmEnvelope; > filter.AmModulator = amEnvelope; > > // Call the Add method in the Voice base class to add all of the > // components to the Voice's component collection. > Add(osc1); > Add(osc2); > Add(filter); > Add(amEnvelope); > Add(fmEnveope); > > } hmmmm......I don't pretend to understand you completely....I think that would take too long, my best approach is to throw hopefully useful suggestions. First I would keep pipes and filters in mind as a picture but possibly do it using decorators, a 'filter' being a specific sort of pipe....despite working in television I actually don't know how audio works....I just know its harder than video....which is easy....so excuse my ignorance, I will use naive abstactions like 'Sound'. (lets ignore the visitor part and assume each pipe is responsible for processing data directly) // your common interface interface IPipe { Sound GetSound(); } class CStateVariableFilter : IPipe { IPipe input1; IPipe input2; CStateVariableFilter(IPipe input1,IPipe input2) { this.input1 = input1; this.input2 = input2; } Sound GetSound() { .... so whatever with the inputs to get the 'sound'. } } // source oscilator class Oscilator : IPipe { Sound GetSound() { ... } } does a filter have to know about the fmModulator and amModulator directly? or can the processing be split into new 'pipes'? if so..... class AmModulator : IPipe { IPipe input; AmModulator(IPipe input) { this.input = input; } Sound GetSound() { .... } } class FmModulator : IPipe { IPipe input; FmModulator(IPipe input) { this.input = input; } Sound GetSound() { .... } } now the client looks something like IPipe CreateVoice() { Oscillator osc1 = new Oscillator(); Oscillator osc2 = new Oscillator(); StateVariableFilter filter = new StateVariableFilter(osc1,osc2); AmModulator amEnvelope = new AmModulator(filter); FmModulator fmEnvelope = new AdsrEnvelope(amEnvelope); return FmModulator; } > > Just a basic synthesizer set up: Two oscillators feeding into one > filter. An envelope modulating the filter's cutoff frequency and another > envelope modulating its amplitude. > > fmEnvelope > osc1--+ | > | v > +-->filter--> > | ^ > osc2--+ | > amEnvelope > > Each of the synth components are added to the base class's collection of > components. They're sorted in ascending order according to their ordinal > number (I've left some details out here such as the functionality for > changing the setup dynamically). > > When it's time for a Voice to synthesize some waveform data, the > Synthesizer calls "Synthesize" on each of the currently playing voices. > In turn, each playing voice calls Synthesize on each of its components: > > public void Synthesize(int startIndex, int count) > { > foreach(ISynthComponent component in components) > { > component.Synthesize(startIndex, count); > } > > } > > That's all there is to it. The order in which Synthesize is called on > each component ensures that the component's buffer is ready to be used > by any connected components. So in our Filter, we could have something > like this: > > public void Synthesize(int startIndex, int count) > { > double in1, in2; > double output; > > for(int i = startIndex; i < startIndex + count; i++) > { > // Access the buffers in the input components. > in1 = input1[i]; // Each component allows index access to its > // buffer. > in2 = input2[i]; > > // Do filtering stuff... > > buffer[i] = output; > } > > } > > And the inputs would be up to date, everything's in sync. > > Anyway, that was a bit longer than I planned on writing. But it gives > you a good idea of the architecture I've been designing. OK I half understand it......I think in my setup the 'Sound' abstraction would correspond to your buffer array. In my construction there should be no need for this 'ordinal' number thing, that I don't completely understand. > > > > > > >> The effect of this approach is that the data processed by one filter > >> is ready to be processed by the next filter; it takes care of the > >> synchronizing problem. Reading data from a filter is a passive > >> operation so several filters can read from the same filter without > >> changing its state. This seems to take care of the problems described > >> above. It also means that the engine that drives all of this can be > >> reused no matter what type of filters are in the pipeline. > > >> It requires, though, that someone know which filter is the ultimate > >> endpoint. It should be the filter with the most connections. One > >> invariant I've thought of implementing is to make sure that there is > >> always one and only one filter that has more connections than any of > >> the others. The engine could recognize this filter as the last one in > >> the chain of filters. > > > personally I don't like it....your processing process now seems to be > > leaking into your representation of the process. > > >> I'd appreciate any thoughts anyone would have on this approach. > >> Thanks. > > > Can you not just pull the data out of the leaves? > > Yeah, that's one possibility. This is realtime processing, though, and I > need to make things as efficient as possible. Mixing the output of > several leaves/components together will take time, so I was thinking > that a reasonable limit to enforce would be to make sure there's always > a root component representing the end of the chain of components. OK, so there should be some sort of 'Mix' pipe at the end....that seens sensible.... > Then > the Voice can just read its data. This endpoint component would just be > the last component in the collection of sorted components. So it would > be easy enough to access provided that the this limit is enforced.- Hide quoted text - OK but the 'stream' of sound that comes out of a synthesiser is 1 stream (OK, we can go into stereo and dolby n:m, but you see what I mean)...... so I think it is reasonable to have a single end 'Mix' pipe......but I'm still not convinced by the adding of components to a simple array and ordering them by this number....it may work....I just think the decorator/pipe filter approach is cleaner.......but I'm not really in a position to judge if it works......only you can say that, > > - Show quoted text -- Hide quoted text - > > - Show quoted text - |
|
#64
| |||
| |||
| On May 6, 7:51 am, S Perryman <q...{}q.net> wrote: > We have a document tool (word processing etc) . > We have a system of objects interacting with eachother : > > Document --- Paragraph --- Line --- Word --- Letter > > When we have a number of objects of all the above types, the system > forms a graph G. The objects are the vertices, the interactions between > objects are the edges. > > The graph is *undirected* because all that is needed is to show where > Word/Letter objects etc interact. > > That given, we can turn to hierarchy. > > A mapping/ordering function M = "composed of" transforms G into a > *directed* graph H : > > Document --> Paragraph --> Line --> Word --> Letter > > Another mapping function M = "used by" produces a different H : > > Letter --> Word --> Line --> Paragraph --> Document > > So in any system (functions, objects etc) it is *G* that is important. > H are just a point of view (literally here) . One H may conflict > with another. G is absolute. It seems to me that even G: > Document --- Paragraph --- Line --- Word --- Letter is a kind of hierarchy. Document is an aggregation of Paragraphs, Paragraphs an aggregation of Lines and so on. What your M & H do is approach an underlying hierarchy from different directions. I do not think hierarchy is required for all programs, but it is often quite useful and contributes to scalability, manageability and reduction of complexity in many programming contexts. Elliott --- The goal of OO is to model a domain as a machine in order to reduce complexity. |
|
#65
| |||
| |||
| Universe wrote: > On May 6, 7:51 am, S Perryman <q...{}q.net> wrote: >>We have a document tool (word processing etc) . >>We have a system of objects interacting with eachother : >>Document --- Paragraph --- Line --- Word --- Letter >>When we have a number of objects of all the above types, the system >>forms a graph G. The objects are the vertices, the interactions between >>objects are the edges. >>The graph is *undirected* because all that is needed is to show where >>Word/Letter objects etc interact. >>That given, we can turn to hierarchy. >>A mapping/ordering function M = "composed of" transforms G into a >>*directed* graph H : >>Document --> Paragraph --> Line --> Word --> Letter >>Another mapping function M = "used by" produces a different H : >>Letter --> Word --> Line --> Paragraph --> Document >>So in any system (functions, objects etc) it is *G* that is important. >>H are just a point of view (literally here) . One H may conflict >>with another. G is absolute. > It seems to me that even G: >>Document --- Paragraph --- Line --- Word --- Letter > is a kind of hierarchy. Document is an aggregation of Paragraphs, > Paragraphs an aggregation of Lines and so on. What your M & H do is > approach an underlying hierarchy from different directions. Which is precisely why G is not a hierarchy. It is M applied to G that defines H, not G by itself. > I do not think hierarchy is required for all programs, but it is often > quite useful and contributes to scalability, manageability and > reduction of complexity in many programming contexts. All hierarchies are useful , that is why humans define them (unless you have time to spare and want to devise myriad M to apply to a G :-) ) . In software development, hierarchy that denotes control, composition, dependency etc for/between components are very useful indeed. Regards, Steven Perryman |
![]() |
| Thread Tools | |
| Display Modes | |
In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.